1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "environment.h"
18
19 #include <inttypes.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/resource.h>
25 #include <sys/utsname.h>
26 #include <unistd.h>
27
28 #include <limits>
29 #include <set>
30 #include <unordered_map>
31 #include <vector>
32
33 #include <android-base/file.h>
34 #include <android-base/logging.h>
35 #include <android-base/parseint.h>
36 #include <android-base/stringprintf.h>
37 #include <android-base/strings.h>
38 #include <procinfo/process.h>
39 #include <procinfo/process_map.h>
40
41 #if defined(__ANDROID__)
42 #include <android-base/properties.h>
43 #endif
44
45 #include "IOEventLoop.h"
46 #include "command.h"
47 #include "event_type.h"
48 #include "kallsyms.h"
49 #include "read_elf.h"
50 #include "thread_tree.h"
51 #include "utils.h"
52 #include "workload.h"
53
54 namespace simpleperf {
55
GetOnlineCpus()56 std::vector<int> GetOnlineCpus() {
57 std::vector<int> result;
58 LineReader reader("/sys/devices/system/cpu/online");
59 if (!reader.Ok()) {
60 PLOG(ERROR) << "can't open online cpu information";
61 return result;
62 }
63
64 std::string* line;
65 if ((line = reader.ReadLine()) != nullptr) {
66 if (auto cpus = GetCpusFromString(*line); cpus) {
67 result.assign(cpus->begin(), cpus->end());
68 }
69 }
70 CHECK(!result.empty()) << "can't get online cpu information";
71 return result;
72 }
73
GetAllModuleFiles(const std::string & path,std::unordered_map<std::string,std::string> * module_file_map)74 static void GetAllModuleFiles(const std::string& path,
75 std::unordered_map<std::string, std::string>* module_file_map) {
76 for (const auto& name : GetEntriesInDir(path)) {
77 std::string entry_path = path + "/" + name;
78 if (IsRegularFile(entry_path) && android::base::EndsWith(name, ".ko")) {
79 std::string module_name = name.substr(0, name.size() - 3);
80 std::replace(module_name.begin(), module_name.end(), '-', '_');
81 module_file_map->insert(std::make_pair(module_name, entry_path));
82 } else if (IsDir(entry_path)) {
83 GetAllModuleFiles(entry_path, module_file_map);
84 }
85 }
86 }
87
GetModulesInUse()88 static std::vector<KernelMmap> GetModulesInUse() {
89 std::vector<KernelMmap> module_mmaps = GetLoadedModules();
90 if (module_mmaps.empty()) {
91 return std::vector<KernelMmap>();
92 }
93 std::unordered_map<std::string, std::string> module_file_map;
94 #if defined(__ANDROID__)
95 // Search directories listed in "File locations" section in
96 // https://source.android.com/devices/architecture/kernel/modular-kernels.
97 for (const auto& path : {"/vendor/lib/modules", "/odm/lib/modules", "/lib/modules"}) {
98 GetAllModuleFiles(path, &module_file_map);
99 }
100 #else
101 utsname uname_buf;
102 if (TEMP_FAILURE_RETRY(uname(&uname_buf)) != 0) {
103 PLOG(ERROR) << "uname() failed";
104 return std::vector<KernelMmap>();
105 }
106 std::string linux_version = uname_buf.release;
107 std::string module_dirpath = "/lib/modules/" + linux_version + "/kernel";
108 GetAllModuleFiles(module_dirpath, &module_file_map);
109 #endif
110 for (auto& module : module_mmaps) {
111 auto it = module_file_map.find(module.name);
112 if (it != module_file_map.end()) {
113 module.filepath = it->second;
114 }
115 }
116 return module_mmaps;
117 }
118
GetKernelAndModuleMmaps(KernelMmap * kernel_mmap,std::vector<KernelMmap> * module_mmaps)119 void GetKernelAndModuleMmaps(KernelMmap* kernel_mmap, std::vector<KernelMmap>* module_mmaps) {
120 kernel_mmap->name = DEFAULT_KERNEL_MMAP_NAME;
121 kernel_mmap->start_addr = 0;
122 kernel_mmap->len = std::numeric_limits<uint64_t>::max();
123 if (uint64_t kstart_addr = GetKernelStartAddress(); kstart_addr != 0) {
124 kernel_mmap->name = std::string(DEFAULT_KERNEL_MMAP_NAME) + "_stext";
125 kernel_mmap->start_addr = kstart_addr;
126 kernel_mmap->len = std::numeric_limits<uint64_t>::max() - kstart_addr;
127 }
128 kernel_mmap->filepath = kernel_mmap->name;
129 *module_mmaps = GetModulesInUse();
130 for (auto& map : *module_mmaps) {
131 if (map.filepath.empty()) {
132 map.filepath = "[" + map.name + "]";
133 }
134 }
135 }
136
ReadThreadNameAndPid(pid_t tid,std::string * comm,pid_t * pid)137 bool ReadThreadNameAndPid(pid_t tid, std::string* comm, pid_t* pid) {
138 android::procinfo::ProcessInfo procinfo;
139 if (!android::procinfo::GetProcessInfo(tid, &procinfo)) {
140 return false;
141 }
142 if (comm != nullptr) {
143 *comm = procinfo.name;
144 }
145 if (pid != nullptr) {
146 *pid = procinfo.pid;
147 }
148 return true;
149 }
150
GetThreadsInProcess(pid_t pid)151 std::vector<pid_t> GetThreadsInProcess(pid_t pid) {
152 std::vector<pid_t> result;
153 android::procinfo::GetProcessTids(pid, &result);
154 return result;
155 }
156
IsThreadAlive(pid_t tid)157 bool IsThreadAlive(pid_t tid) {
158 return IsDir(android::base::StringPrintf("/proc/%d", tid));
159 }
160
GetProcessForThread(pid_t tid,pid_t * pid)161 bool GetProcessForThread(pid_t tid, pid_t* pid) {
162 return ReadThreadNameAndPid(tid, nullptr, pid);
163 }
164
GetThreadName(pid_t tid,std::string * name)165 bool GetThreadName(pid_t tid, std::string* name) {
166 return ReadThreadNameAndPid(tid, name, nullptr);
167 }
168
GetAllProcesses()169 std::vector<pid_t> GetAllProcesses() {
170 std::vector<pid_t> result;
171 std::vector<std::string> entries = GetEntriesInDir("/proc");
172 for (const auto& entry : entries) {
173 pid_t pid;
174 if (!android::base::ParseInt(entry.c_str(), &pid, 0)) {
175 continue;
176 }
177 result.push_back(pid);
178 }
179 return result;
180 }
181
GetThreadMmapsInProcess(pid_t pid,std::vector<ThreadMmap> * thread_mmaps)182 bool GetThreadMmapsInProcess(pid_t pid, std::vector<ThreadMmap>* thread_mmaps) {
183 thread_mmaps->clear();
184 return android::procinfo::ReadProcessMaps(pid, [&](const android::procinfo::MapInfo& mapinfo) {
185 thread_mmaps->emplace_back(mapinfo.start, mapinfo.end - mapinfo.start, mapinfo.pgoff,
186 mapinfo.name.c_str(), mapinfo.flags);
187 });
188 }
189
GetKernelBuildId(BuildId * build_id)190 bool GetKernelBuildId(BuildId* build_id) {
191 ElfStatus result = GetBuildIdFromNoteFile("/sys/kernel/notes", build_id);
192 if (result != ElfStatus::NO_ERROR) {
193 LOG(DEBUG) << "failed to read /sys/kernel/notes: " << result;
194 }
195 return result == ElfStatus::NO_ERROR;
196 }
197
GetModuleBuildId(const std::string & module_name,BuildId * build_id,const std::string & sysfs_dir)198 bool GetModuleBuildId(const std::string& module_name, BuildId* build_id,
199 const std::string& sysfs_dir) {
200 std::string notefile = sysfs_dir + "/module/" + module_name + "/notes/.note.gnu.build-id";
201 return GetBuildIdFromNoteFile(notefile, build_id) == ElfStatus::NO_ERROR;
202 }
203
204 /*
205 * perf event allow level:
206 * -1 - everything allowed
207 * 0 - disallow raw tracepoint access for unpriv
208 * 1 - disallow cpu events for unpriv
209 * 2 - disallow kernel profiling for unpriv
210 * 3 - disallow user profiling for unpriv
211 */
212 static const char* perf_event_allow_path = "/proc/sys/kernel/perf_event_paranoid";
213
ReadPerfEventAllowStatus(int * value)214 static bool ReadPerfEventAllowStatus(int* value) {
215 std::string s;
216 if (!android::base::ReadFileToString(perf_event_allow_path, &s)) {
217 PLOG(DEBUG) << "failed to read " << perf_event_allow_path;
218 return false;
219 }
220 s = android::base::Trim(s);
221 if (!android::base::ParseInt(s.c_str(), value)) {
222 PLOG(ERROR) << "failed to parse " << perf_event_allow_path << ": " << s;
223 return false;
224 }
225 return true;
226 }
227
CanRecordRawData()228 bool CanRecordRawData() {
229 if (IsRoot()) {
230 return true;
231 }
232 #if defined(__ANDROID__)
233 // Android R uses selinux to control perf_event_open. Whether raw data can be recorded is hard
234 // to check unless we really try it. And probably there is no need to record raw data in non-root
235 // users.
236 return false;
237 #else
238 int value;
239 return ReadPerfEventAllowStatus(&value) && value == -1;
240 #endif
241 }
242
GetLimitLevelDescription(int limit_level)243 static const char* GetLimitLevelDescription(int limit_level) {
244 switch (limit_level) {
245 case -1:
246 return "unlimited";
247 case 0:
248 return "disallowing raw tracepoint access for unpriv";
249 case 1:
250 return "disallowing cpu events for unpriv";
251 case 2:
252 return "disallowing kernel profiling for unpriv";
253 case 3:
254 return "disallowing user profiling for unpriv";
255 default:
256 return "unknown level";
257 }
258 }
259
CheckPerfEventLimit()260 bool CheckPerfEventLimit() {
261 // Root is not limited by perf_event_allow_path. However, the monitored threads
262 // may create child processes not running as root. To make sure the child processes have
263 // enough permission to create inherited tracepoint events, write -1 to perf_event_allow_path.
264 // See http://b/62230699.
265 if (IsRoot()) {
266 if (android::base::WriteStringToFile("-1", perf_event_allow_path)) {
267 return true;
268 }
269 // On host, we may not be able to write to perf_event_allow_path (like when running in docker).
270 #if defined(__ANDROID__)
271 PLOG(ERROR) << "failed to write -1 to " << perf_event_allow_path;
272 return false;
273 #endif
274 }
275 int limit_level;
276 bool can_read_allow_file = ReadPerfEventAllowStatus(&limit_level);
277 if (can_read_allow_file && limit_level <= 1) {
278 return true;
279 }
280 #if defined(__ANDROID__)
281 const std::string prop_name = "security.perf_harden";
282 std::string prop_value = android::base::GetProperty(prop_name, "");
283 if (prop_value.empty()) {
284 // can't do anything if there is no such property.
285 return true;
286 }
287 if (prop_value == "0") {
288 return true;
289 }
290 // Try to enable perf events by setprop security.perf_harden=0.
291 if (android::base::SetProperty(prop_name, "0")) {
292 sleep(1);
293 if (can_read_allow_file && ReadPerfEventAllowStatus(&limit_level) && limit_level <= 1) {
294 return true;
295 }
296 if (android::base::GetProperty(prop_name, "") == "0") {
297 return true;
298 }
299 }
300 if (can_read_allow_file) {
301 LOG(WARNING) << perf_event_allow_path << " is " << limit_level << ", "
302 << GetLimitLevelDescription(limit_level) << ".";
303 }
304 LOG(WARNING) << "Try using `adb shell setprop security.perf_harden 0` to allow profiling.";
305 return false;
306 #else
307 if (can_read_allow_file) {
308 LOG(WARNING) << perf_event_allow_path << " is " << limit_level << ", "
309 << GetLimitLevelDescription(limit_level) << ".";
310 return false;
311 }
312 #endif
313 return true;
314 }
315
316 #if defined(__ANDROID__)
SetProperty(const char * prop_name,uint64_t value)317 static bool SetProperty(const char* prop_name, uint64_t value) {
318 if (!android::base::SetProperty(prop_name, std::to_string(value))) {
319 LOG(ERROR) << "Failed to SetProperty " << prop_name << " to " << value;
320 return false;
321 }
322 return true;
323 }
324
SetPerfEventLimits(uint64_t sample_freq,size_t cpu_percent,uint64_t mlock_kb)325 bool SetPerfEventLimits(uint64_t sample_freq, size_t cpu_percent, uint64_t mlock_kb) {
326 if (!SetProperty("debug.perf_event_max_sample_rate", sample_freq) ||
327 !SetProperty("debug.perf_cpu_time_max_percent", cpu_percent) ||
328 !SetProperty("debug.perf_event_mlock_kb", mlock_kb) ||
329 !SetProperty("security.perf_harden", 0)) {
330 return false;
331 }
332 // Wait for init process to change perf event limits based on properties.
333 const size_t max_wait_us = 3 * 1000000;
334 int finish_mask = 0;
335 for (size_t i = 0; i < max_wait_us && finish_mask != 7; ++i) {
336 usleep(1); // Wait 1us to avoid busy loop.
337 if ((finish_mask & 1) == 0) {
338 uint64_t freq;
339 if (!GetMaxSampleFrequency(&freq) || freq == sample_freq) {
340 finish_mask |= 1;
341 }
342 }
343 if ((finish_mask & 2) == 0) {
344 size_t percent;
345 if (!GetCpuTimeMaxPercent(&percent) || percent == cpu_percent) {
346 finish_mask |= 2;
347 }
348 }
349 if ((finish_mask & 4) == 0) {
350 uint64_t kb;
351 if (!GetPerfEventMlockKb(&kb) || kb == mlock_kb) {
352 finish_mask |= 4;
353 }
354 }
355 }
356 if (finish_mask != 7) {
357 LOG(WARNING) << "Wait setting perf event limits timeout";
358 }
359 return true;
360 }
361 #else // !defined(__ANDROID__)
SetPerfEventLimits(uint64_t,size_t,uint64_t)362 bool SetPerfEventLimits(uint64_t, size_t, uint64_t) {
363 return true;
364 }
365 #endif
366
367 template <typename T>
ReadUintFromProcFile(const std::string & path,T * value)368 static bool ReadUintFromProcFile(const std::string& path, T* value) {
369 std::string s;
370 if (!android::base::ReadFileToString(path, &s)) {
371 PLOG(DEBUG) << "failed to read " << path;
372 return false;
373 }
374 s = android::base::Trim(s);
375 if (!android::base::ParseUint(s.c_str(), value)) {
376 LOG(ERROR) << "failed to parse " << path << ": " << s;
377 return false;
378 }
379 return true;
380 }
381
382 template <typename T>
WriteUintToProcFile(const std::string & path,T value)383 static bool WriteUintToProcFile(const std::string& path, T value) {
384 if (IsRoot()) {
385 return android::base::WriteStringToFile(std::to_string(value), path);
386 }
387 return false;
388 }
389
GetMaxSampleFrequency(uint64_t * max_sample_freq)390 bool GetMaxSampleFrequency(uint64_t* max_sample_freq) {
391 return ReadUintFromProcFile("/proc/sys/kernel/perf_event_max_sample_rate", max_sample_freq);
392 }
393
SetMaxSampleFrequency(uint64_t max_sample_freq)394 bool SetMaxSampleFrequency(uint64_t max_sample_freq) {
395 return WriteUintToProcFile("/proc/sys/kernel/perf_event_max_sample_rate", max_sample_freq);
396 }
397
GetCpuTimeMaxPercent(size_t * percent)398 bool GetCpuTimeMaxPercent(size_t* percent) {
399 return ReadUintFromProcFile("/proc/sys/kernel/perf_cpu_time_max_percent", percent);
400 }
401
SetCpuTimeMaxPercent(size_t percent)402 bool SetCpuTimeMaxPercent(size_t percent) {
403 return WriteUintToProcFile("/proc/sys/kernel/perf_cpu_time_max_percent", percent);
404 }
405
GetPerfEventMlockKb(uint64_t * mlock_kb)406 bool GetPerfEventMlockKb(uint64_t* mlock_kb) {
407 return ReadUintFromProcFile("/proc/sys/kernel/perf_event_mlock_kb", mlock_kb);
408 }
409
SetPerfEventMlockKb(uint64_t mlock_kb)410 bool SetPerfEventMlockKb(uint64_t mlock_kb) {
411 return WriteUintToProcFile("/proc/sys/kernel/perf_event_mlock_kb", mlock_kb);
412 }
413
GetMachineArch()414 ArchType GetMachineArch() {
415 #if defined(__i386__)
416 // For 32 bit x86 build, we can't get machine arch by uname().
417 ArchType arch = ARCH_UNSUPPORTED;
418 std::unique_ptr<FILE, decltype(&pclose)> fp(popen("uname -m", "re"), pclose);
419 if (fp) {
420 char machine[40];
421 if (fgets(machine, sizeof(machine), fp.get()) == machine) {
422 arch = GetArchType(android::base::Trim(machine));
423 }
424 }
425 #else
426 utsname uname_buf;
427 if (TEMP_FAILURE_RETRY(uname(&uname_buf)) != 0) {
428 PLOG(WARNING) << "uname() failed";
429 return GetBuildArch();
430 }
431 ArchType arch = GetArchType(uname_buf.machine);
432 #endif
433 if (arch != ARCH_UNSUPPORTED) {
434 return arch;
435 }
436 return GetBuildArch();
437 }
438
PrepareVdsoFile()439 void PrepareVdsoFile() {
440 // vdso is an elf file in memory loaded in each process's user space by the kernel. To read
441 // symbols from it and unwind through it, we need to dump it into a file in storage.
442 // It doesn't affect much when failed to prepare vdso file, so there is no need to return values.
443 std::vector<ThreadMmap> thread_mmaps;
444 if (!GetThreadMmapsInProcess(getpid(), &thread_mmaps)) {
445 return;
446 }
447 const ThreadMmap* vdso_map = nullptr;
448 for (const auto& map : thread_mmaps) {
449 if (map.name == "[vdso]") {
450 vdso_map = ↦
451 break;
452 }
453 }
454 if (vdso_map == nullptr) {
455 return;
456 }
457 std::string s(vdso_map->len, '\0');
458 memcpy(&s[0], reinterpret_cast<void*>(static_cast<uintptr_t>(vdso_map->start_addr)),
459 vdso_map->len);
460 std::unique_ptr<TemporaryFile> tmpfile = ScopedTempFiles::CreateTempFile();
461 if (!android::base::WriteStringToFd(s, tmpfile->fd)) {
462 return;
463 }
464 Dso::SetVdsoFile(tmpfile->path, sizeof(size_t) == sizeof(uint64_t));
465 }
466
HasOpenedAppApkFile(int pid)467 static bool HasOpenedAppApkFile(int pid) {
468 std::string fd_path = "/proc/" + std::to_string(pid) + "/fd/";
469 std::vector<std::string> files = GetEntriesInDir(fd_path);
470 for (const auto& file : files) {
471 std::string real_path;
472 if (!android::base::Readlink(fd_path + file, &real_path)) {
473 continue;
474 }
475 if (real_path.find("app") != std::string::npos && real_path.find(".apk") != std::string::npos) {
476 return true;
477 }
478 }
479 return false;
480 }
481
WaitForAppProcesses(const std::string & package_name)482 std::set<pid_t> WaitForAppProcesses(const std::string& package_name) {
483 std::set<pid_t> result;
484 size_t loop_count = 0;
485 while (true) {
486 std::vector<pid_t> pids = GetAllProcesses();
487 for (pid_t pid : pids) {
488 std::string cmdline;
489 if (!android::base::ReadFileToString("/proc/" + std::to_string(pid) + "/cmdline", &cmdline)) {
490 // Maybe we don't have permission to read it.
491 continue;
492 }
493 std::string process_name = android::base::Basename(cmdline);
494 // The app may have multiple processes, with process name like
495 // com.google.android.googlequicksearchbox:search.
496 size_t split_pos = process_name.find(':');
497 if (split_pos != std::string::npos) {
498 process_name = process_name.substr(0, split_pos);
499 }
500 if (process_name != package_name) {
501 continue;
502 }
503 // If a debuggable app with wrap.sh runs on Android O, the app will be started with
504 // logwrapper as below:
505 // 1. Zygote forks a child process, rename it to package_name.
506 // 2. The child process execute sh, which starts a child process running
507 // /system/bin/logwrapper.
508 // 3. logwrapper starts a child process running sh, which interprets wrap.sh.
509 // 4. wrap.sh starts a child process running the app.
510 // The problem here is we want to profile the process started in step 4, but sometimes we
511 // run into the process started in step 1. To solve it, we can check if the process has
512 // opened an apk file in some app dirs.
513 if (!HasOpenedAppApkFile(pid)) {
514 continue;
515 }
516 if (loop_count > 0u) {
517 LOG(INFO) << "Got process " << pid << " for package " << package_name;
518 }
519 result.insert(pid);
520 }
521 if (!result.empty()) {
522 return result;
523 }
524 if (++loop_count == 1u) {
525 LOG(INFO) << "Waiting for process of app " << package_name;
526 }
527 usleep(1000);
528 }
529 }
530
531 namespace {
532
IsAppDebuggable(int user_id,const std::string & package_name)533 bool IsAppDebuggable(int user_id, const std::string& package_name) {
534 return Workload::RunCmd({"run-as", package_name, "--user", std::to_string(user_id), "echo",
535 ">/dev/null", "2>/dev/null"},
536 false);
537 }
538
539 class InAppRunner {
540 public:
InAppRunner(int user_id,const std::string & package_name)541 InAppRunner(int user_id, const std::string& package_name)
542 : user_id_(std::to_string(user_id)), package_name_(package_name) {}
~InAppRunner()543 virtual ~InAppRunner() {
544 if (!tracepoint_file_.empty()) {
545 unlink(tracepoint_file_.c_str());
546 }
547 }
548 virtual bool Prepare() = 0;
549 bool RunCmdInApp(const std::string& cmd, const std::vector<std::string>& args,
550 size_t workload_args_size, const std::string& output_filepath,
551 bool need_tracepoint_events);
552
553 protected:
554 virtual std::vector<std::string> GetPrefixArgs(const std::string& cmd) = 0;
555
556 const std::string user_id_;
557 const std::string package_name_;
558 std::string tracepoint_file_;
559 };
560
RunCmdInApp(const std::string & cmd,const std::vector<std::string> & cmd_args,size_t workload_args_size,const std::string & output_filepath,bool need_tracepoint_events)561 bool InAppRunner::RunCmdInApp(const std::string& cmd, const std::vector<std::string>& cmd_args,
562 size_t workload_args_size, const std::string& output_filepath,
563 bool need_tracepoint_events) {
564 // 1. Build cmd args running in app's context.
565 std::vector<std::string> args = GetPrefixArgs(cmd);
566 args.insert(args.end(), {"--in-app", "--log", GetLogSeverityName()});
567 if (log_to_android_buffer) {
568 args.emplace_back("--log-to-android-buffer");
569 }
570 if (need_tracepoint_events) {
571 // Since we can't read tracepoint events from tracefs in app's context, we need to prepare
572 // them in tracepoint_file in shell's context, and pass the path of tracepoint_file to the
573 // child process using --tracepoint-events option.
574 const std::string tracepoint_file = "/data/local/tmp/tracepoint_events";
575 if (!EventTypeManager::Instance().WriteTracepointsToFile(tracepoint_file)) {
576 PLOG(ERROR) << "Failed to store tracepoint events";
577 return false;
578 }
579 tracepoint_file_ = tracepoint_file;
580 args.insert(args.end(), {"--tracepoint-events", tracepoint_file_});
581 }
582
583 android::base::unique_fd out_fd;
584 if (!output_filepath.empty()) {
585 // A process running in app's context can't open a file outside it's data directory to write.
586 // So pass it a file descriptor to write.
587 out_fd = FileHelper::OpenWriteOnly(output_filepath);
588 if (out_fd == -1) {
589 PLOG(ERROR) << "Failed to open " << output_filepath;
590 return false;
591 }
592 args.insert(args.end(), {"--out-fd", std::to_string(int(out_fd))});
593 }
594
595 // We can't send signal to a process running in app's context. So use a pipe file to send stop
596 // signal.
597 android::base::unique_fd stop_signal_rfd;
598 android::base::unique_fd stop_signal_wfd;
599 if (!android::base::Pipe(&stop_signal_rfd, &stop_signal_wfd, 0)) {
600 PLOG(ERROR) << "pipe";
601 return false;
602 }
603 args.insert(args.end(), {"--stop-signal-fd", std::to_string(int(stop_signal_rfd))});
604
605 for (size_t i = 0; i < cmd_args.size(); ++i) {
606 if (i < cmd_args.size() - workload_args_size) {
607 // Omit "-o output_file". It is replaced by "--out-fd fd".
608 if (cmd_args[i] == "-o" || cmd_args[i] == "--app") {
609 i++;
610 continue;
611 }
612 }
613 args.push_back(cmd_args[i]);
614 }
615 char* argv[args.size() + 1];
616 for (size_t i = 0; i < args.size(); ++i) {
617 argv[i] = &args[i][0];
618 }
619 argv[args.size()] = nullptr;
620
621 // 2. Run child process in app's context.
622 auto ChildProcFn = [&]() {
623 stop_signal_wfd.reset();
624 execvp(argv[0], argv);
625 exit(1);
626 };
627 std::unique_ptr<Workload> workload = Workload::CreateWorkload(ChildProcFn);
628 if (!workload) {
629 return false;
630 }
631 stop_signal_rfd.reset();
632
633 // Wait on signals.
634 IOEventLoop loop;
635 bool need_to_stop_child = false;
636 std::vector<int> stop_signals = {SIGINT, SIGTERM};
637 if (!SignalIsIgnored(SIGHUP)) {
638 stop_signals.push_back(SIGHUP);
639 }
640 if (!loop.AddSignalEvents(stop_signals, [&]() {
641 need_to_stop_child = true;
642 return loop.ExitLoop();
643 })) {
644 return false;
645 }
646 if (!loop.AddSignalEvent(SIGCHLD, [&]() { return loop.ExitLoop(); })) {
647 return false;
648 }
649
650 if (!workload->Start()) {
651 return false;
652 }
653 if (!loop.RunLoop()) {
654 return false;
655 }
656 if (need_to_stop_child) {
657 stop_signal_wfd.reset();
658 }
659 int exit_code;
660 if (!workload->WaitChildProcess(&exit_code) || exit_code != 0) {
661 return false;
662 }
663 return true;
664 }
665
666 class RunAs : public InAppRunner {
667 public:
RunAs(int user_id,const std::string & package_name)668 RunAs(int user_id, const std::string& package_name) : InAppRunner(user_id, package_name) {}
~RunAs()669 virtual ~RunAs() {
670 if (simpleperf_copied_in_app_) {
671 Workload::RunCmd({"run-as", package_name_, "--user", user_id_, "rm", "-rf", "simpleperf"});
672 }
673 }
674 bool Prepare() override;
675
676 protected:
GetPrefixArgs(const std::string & cmd)677 std::vector<std::string> GetPrefixArgs(const std::string& cmd) {
678 std::vector<std::string> args = {"run-as",
679 package_name_,
680 "--user",
681 user_id_,
682 simpleperf_copied_in_app_ ? "./simpleperf" : simpleperf_path_,
683 cmd,
684 "--app",
685 package_name_};
686 if (cmd == "record") {
687 if (simpleperf_copied_in_app_ || GetAndroidVersion() >= kAndroidVersionS) {
688 args.emplace_back("--add-meta-info");
689 args.emplace_back("app_type=debuggable");
690 }
691 }
692 return args;
693 }
694
695 bool simpleperf_copied_in_app_ = false;
696 std::string simpleperf_path_;
697 };
698
Prepare()699 bool RunAs::Prepare() {
700 // run-as can't run /data/local/tmp/simpleperf directly. So copy simpleperf binary if needed.
701 if (!android::base::Readlink("/proc/self/exe", &simpleperf_path_)) {
702 PLOG(ERROR) << "ReadLink failed";
703 return false;
704 }
705 if (simpleperf_path_.find("CtsSimpleperfTest") != std::string::npos) {
706 simpleperf_path_ = "/system/bin/simpleperf";
707 return true;
708 }
709 if (android::base::StartsWith(simpleperf_path_, "/system")) {
710 return true;
711 }
712 if (!Workload::RunCmd(
713 {"run-as", package_name_, "--user", user_id_, "cp", simpleperf_path_, "simpleperf"})) {
714 return false;
715 }
716 simpleperf_copied_in_app_ = true;
717 return true;
718 }
719
720 class SimpleperfAppRunner : public InAppRunner {
721 public:
SimpleperfAppRunner(int user_id,const std::string & package_name,const std::string app_type)722 SimpleperfAppRunner(int user_id, const std::string& package_name, const std::string app_type)
723 : InAppRunner(user_id, package_name) {
724 // On Android < S, the app type is unknown before running simpleperf_app_runner. Assume it's
725 // profileable.
726 app_type_ = app_type == "unknown" ? "profileable" : app_type;
727 }
Prepare()728 bool Prepare() override { return GetAndroidVersion() >= kAndroidVersionQ; }
729
730 protected:
GetPrefixArgs(const std::string & cmd)731 std::vector<std::string> GetPrefixArgs(const std::string& cmd) {
732 std::vector<std::string> args = {"simpleperf_app_runner", package_name_};
733 if (user_id_ != "0") {
734 args.emplace_back("--user");
735 args.emplace_back(user_id_);
736 }
737 args.emplace_back(cmd);
738 if (cmd == "record" && GetAndroidVersion() >= kAndroidVersionS) {
739 args.emplace_back("--add-meta-info");
740 args.emplace_back("app_type=" + app_type_);
741 }
742 return args;
743 }
744
745 std::string app_type_;
746 };
747
748 } // namespace
749
750 static bool allow_run_as = true;
751 static bool allow_simpleperf_app_runner = true;
752
SetRunInAppToolForTesting(bool run_as,bool simpleperf_app_runner)753 void SetRunInAppToolForTesting(bool run_as, bool simpleperf_app_runner) {
754 allow_run_as = run_as;
755 allow_simpleperf_app_runner = simpleperf_app_runner;
756 }
757
GetCurrentUserId()758 static int GetCurrentUserId() {
759 std::unique_ptr<FILE, decltype(&pclose)> fd(popen("am get-current-user", "r"), pclose);
760 if (fd) {
761 char buf[128];
762 if (fgets(buf, sizeof(buf), fd.get()) != nullptr) {
763 int user_id;
764 if (android::base::ParseInt(android::base::Trim(buf), &user_id, 0)) {
765 return user_id;
766 }
767 }
768 }
769 return 0;
770 }
771
GetAppType(const std::string & app_package_name)772 std::string GetAppType(const std::string& app_package_name) {
773 if (GetAndroidVersion() < kAndroidVersionS) {
774 return "unknown";
775 }
776 std::string cmd = "simpleperf_app_runner " + app_package_name + " --show-app-type";
777 std::unique_ptr<FILE, decltype(&pclose)> fp(popen(cmd.c_str(), "re"), pclose);
778 if (fp) {
779 char buf[128];
780 if (fgets(buf, sizeof(buf), fp.get()) != nullptr) {
781 return android::base::Trim(buf);
782 }
783 }
784 // Can't get app_type. It means the app doesn't exist.
785 return "not_exist";
786 }
787
RunInAppContext(const std::string & app_package_name,const std::string & cmd,const std::vector<std::string> & args,size_t workload_args_size,const std::string & output_filepath,bool need_tracepoint_events)788 bool RunInAppContext(const std::string& app_package_name, const std::string& cmd,
789 const std::vector<std::string>& args, size_t workload_args_size,
790 const std::string& output_filepath, bool need_tracepoint_events) {
791 int user_id = GetCurrentUserId();
792 std::unique_ptr<InAppRunner> in_app_runner;
793
794 std::string app_type = GetAppType(app_package_name);
795 if (app_type == "unknown" && IsAppDebuggable(user_id, app_package_name)) {
796 app_type = "debuggable";
797 }
798
799 if (allow_run_as && app_type == "debuggable") {
800 in_app_runner.reset(new RunAs(user_id, app_package_name));
801 if (!in_app_runner->Prepare()) {
802 in_app_runner = nullptr;
803 }
804 }
805 if (!in_app_runner && allow_simpleperf_app_runner) {
806 if (app_type == "debuggable" || app_type == "profileable" || app_type == "unknown") {
807 in_app_runner.reset(new SimpleperfAppRunner(user_id, app_package_name, app_type));
808 if (!in_app_runner->Prepare()) {
809 in_app_runner = nullptr;
810 }
811 }
812 }
813 if (!in_app_runner) {
814 LOG(ERROR) << "Package " << app_package_name
815 << " doesn't exist or isn't debuggable/profileable.";
816 return false;
817 }
818 return in_app_runner->RunCmdInApp(cmd, args, workload_args_size, output_filepath,
819 need_tracepoint_events);
820 }
821
AllowMoreOpenedFiles()822 void AllowMoreOpenedFiles() {
823 // On Android <= O, the hard limit is 4096, and the soft limit is 1024.
824 // On Android >= P, both the hard and soft limit are 32768.
825 rlimit limit;
826 if (getrlimit(RLIMIT_NOFILE, &limit) == 0) {
827 limit.rlim_cur = limit.rlim_max;
828 setrlimit(RLIMIT_NOFILE, &limit);
829 }
830 }
831
832 std::string ScopedTempFiles::tmp_dir_;
833 std::vector<std::string> ScopedTempFiles::files_to_delete_;
834
Create(const std::string & tmp_dir)835 std::unique_ptr<ScopedTempFiles> ScopedTempFiles::Create(const std::string& tmp_dir) {
836 if (access(tmp_dir.c_str(), W_OK | X_OK) != 0) {
837 return nullptr;
838 }
839 return std::unique_ptr<ScopedTempFiles>(new ScopedTempFiles(tmp_dir));
840 }
841
ScopedTempFiles(const std::string & tmp_dir)842 ScopedTempFiles::ScopedTempFiles(const std::string& tmp_dir) {
843 CHECK(tmp_dir_.empty()); // No other ScopedTempFiles.
844 tmp_dir_ = tmp_dir;
845 }
846
~ScopedTempFiles()847 ScopedTempFiles::~ScopedTempFiles() {
848 tmp_dir_.clear();
849 for (auto& file : files_to_delete_) {
850 unlink(file.c_str());
851 }
852 files_to_delete_.clear();
853 }
854
CreateTempFile(bool delete_in_destructor)855 std::unique_ptr<TemporaryFile> ScopedTempFiles::CreateTempFile(bool delete_in_destructor) {
856 CHECK(!tmp_dir_.empty());
857 std::unique_ptr<TemporaryFile> tmp_file(new TemporaryFile(tmp_dir_));
858 CHECK_NE(tmp_file->fd, -1) << "failed to create tmpfile under " << tmp_dir_;
859 if (delete_in_destructor) {
860 tmp_file->DoNotRemove();
861 files_to_delete_.push_back(tmp_file->path);
862 }
863 return tmp_file;
864 }
865
RegisterTempFile(const std::string & path)866 void ScopedTempFiles::RegisterTempFile(const std::string& path) {
867 files_to_delete_.emplace_back(path);
868 }
869
SignalIsIgnored(int signo)870 bool SignalIsIgnored(int signo) {
871 struct sigaction act;
872 if (sigaction(signo, nullptr, &act) != 0) {
873 PLOG(FATAL) << "failed to query signal handler for signal " << signo;
874 }
875
876 if ((act.sa_flags & SA_SIGINFO)) {
877 return false;
878 }
879
880 return act.sa_handler == SIG_IGN;
881 }
882
GetAndroidVersion()883 int GetAndroidVersion() {
884 #if defined(__ANDROID__)
885 static int android_version = -1;
886 if (android_version == -1) {
887 android_version = 0;
888 std::string s = android::base::GetProperty("ro.build.version.codename", "REL");
889 if (s == "REL") {
890 s = android::base::GetProperty("ro.build.version.release", "");
891 }
892 // The release string can be a list of numbers (like 8.1.0), a character (like Q)
893 // or many characters (like OMR1).
894 if (!s.empty()) {
895 // Each Android version has a version number: L is 5, M is 6, N is 7, O is 8, etc.
896 if (s[0] >= 'A' && s[0] <= 'Z') {
897 android_version = s[0] - 'P' + kAndroidVersionP;
898 } else if (isdigit(s[0])) {
899 sscanf(s.c_str(), "%d", &android_version);
900 }
901 }
902 }
903 return android_version;
904 #else // defined(__ANDROID__)
905 return 0;
906 #endif
907 }
908
GetHardwareFromCpuInfo(const std::string & cpu_info)909 std::string GetHardwareFromCpuInfo(const std::string& cpu_info) {
910 for (auto& line : android::base::Split(cpu_info, "\n")) {
911 size_t pos = line.find(':');
912 if (pos != std::string::npos) {
913 std::string key = android::base::Trim(line.substr(0, pos));
914 if (key == "Hardware") {
915 return android::base::Trim(line.substr(pos + 1));
916 }
917 }
918 }
919 return "";
920 }
921
MappedFileOnlyExistInMemory(const char * filename)922 bool MappedFileOnlyExistInMemory(const char* filename) {
923 // Mapped files only existing in memory:
924 // empty name
925 // [anon:???]
926 // [stack]
927 // /dev/*
928 // //anon: generated by kernel/events/core.c.
929 // /memfd: created by memfd_create.
930 return filename[0] == '\0' || (filename[0] == '[' && strcmp(filename, "[vdso]") != 0) ||
931 strncmp(filename, "//", 2) == 0 || strncmp(filename, "/dev/", 5) == 0 ||
932 strncmp(filename, "/memfd:", 7) == 0;
933 }
934
GetCompleteProcessName(pid_t pid)935 std::string GetCompleteProcessName(pid_t pid) {
936 std::string s;
937 if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid), &s)) {
938 s.clear();
939 }
940 for (size_t i = 0; i < s.size(); ++i) {
941 // /proc/pid/cmdline uses 0 to separate arguments.
942 if (isspace(s[i]) || s[i] == 0) {
943 s.resize(i);
944 break;
945 }
946 }
947 return s;
948 }
949
GetTraceFsDir()950 const char* GetTraceFsDir() {
951 static const char* tracefs_dir = nullptr;
952 if (tracefs_dir == nullptr) {
953 for (const char* path : {"/sys/kernel/debug/tracing", "/sys/kernel/tracing"}) {
954 if (IsDir(path)) {
955 tracefs_dir = path;
956 break;
957 }
958 }
959 }
960 return tracefs_dir;
961 }
962
GetKernelVersion()963 std::optional<std::pair<int, int>> GetKernelVersion() {
964 utsname uname_buf;
965 int major;
966 int minor;
967 if (TEMP_FAILURE_RETRY(uname(&uname_buf)) != 0 ||
968 sscanf(uname_buf.release, "%d.%d", &major, &minor) != 2) {
969 return std::nullopt;
970 }
971 return std::make_pair(major, minor);
972 }
973
GetProcessUid(pid_t pid)974 std::optional<uid_t> GetProcessUid(pid_t pid) {
975 std::string status_file = "/proc/" + std::to_string(pid) + "/status";
976 LineReader reader(status_file);
977 if (!reader.Ok()) {
978 return std::nullopt;
979 }
980
981 std::string* line;
982 while ((line = reader.ReadLine()) != nullptr) {
983 if (android::base::StartsWith(*line, "Uid:")) {
984 uid_t uid;
985 if (sscanf(line->data() + strlen("Uid:"), "%u", &uid) == 1) {
986 return uid;
987 }
988 }
989 }
990 return std::nullopt;
991 }
992
993 } // namespace simpleperf
994