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 <sys/resource.h>
24 #include <sys/utsname.h>
25
26 #include <limits>
27 #include <set>
28 #include <unordered_map>
29 #include <vector>
30
31 #include <android-base/file.h>
32 #include <android-base/logging.h>
33 #include <android-base/parseint.h>
34 #include <android-base/strings.h>
35 #include <android-base/stringprintf.h>
36 #include <procinfo/process.h>
37
38 #if defined(__ANDROID__)
39 #include <android-base/properties.h>
40 #endif
41
42 #include "event_type.h"
43 #include "IOEventLoop.h"
44 #include "read_elf.h"
45 #include "thread_tree.h"
46 #include "utils.h"
47 #include "workload.h"
48
49 class LineReader {
50 public:
LineReader(FILE * fp)51 explicit LineReader(FILE* fp) : fp_(fp), buf_(nullptr), bufsize_(0) {
52 }
53
~LineReader()54 ~LineReader() {
55 free(buf_);
56 fclose(fp_);
57 }
58
ReadLine()59 char* ReadLine() {
60 if (getline(&buf_, &bufsize_, fp_) != -1) {
61 return buf_;
62 }
63 return nullptr;
64 }
65
MaxLineSize()66 size_t MaxLineSize() {
67 return bufsize_;
68 }
69
70 private:
71 FILE* fp_;
72 char* buf_;
73 size_t bufsize_;
74 };
75
GetOnlineCpus()76 std::vector<int> GetOnlineCpus() {
77 std::vector<int> result;
78 FILE* fp = fopen("/sys/devices/system/cpu/online", "re");
79 if (fp == nullptr) {
80 PLOG(ERROR) << "can't open online cpu information";
81 return result;
82 }
83
84 LineReader reader(fp);
85 char* line;
86 if ((line = reader.ReadLine()) != nullptr) {
87 result = GetCpusFromString(line);
88 }
89 CHECK(!result.empty()) << "can't get online cpu information";
90 return result;
91 }
92
GetCpusFromString(const std::string & s)93 std::vector<int> GetCpusFromString(const std::string& s) {
94 std::set<int> cpu_set;
95 bool have_dash = false;
96 const char* p = s.c_str();
97 char* endp;
98 int last_cpu;
99 int cpu;
100 // Parse line like: 0,1-3, 5, 7-8
101 while ((cpu = static_cast<int>(strtol(p, &endp, 10))) != 0 || endp != p) {
102 if (have_dash && !cpu_set.empty()) {
103 for (int t = last_cpu + 1; t < cpu; ++t) {
104 cpu_set.insert(t);
105 }
106 }
107 have_dash = false;
108 cpu_set.insert(cpu);
109 last_cpu = cpu;
110 p = endp;
111 while (!isdigit(*p) && *p != '\0') {
112 if (*p == '-') {
113 have_dash = true;
114 }
115 ++p;
116 }
117 }
118 return std::vector<int>(cpu_set.begin(), cpu_set.end());
119 }
120
GetLoadedModules()121 static std::vector<KernelMmap> GetLoadedModules() {
122 std::vector<KernelMmap> result;
123 FILE* fp = fopen("/proc/modules", "re");
124 if (fp == nullptr) {
125 // There is no /proc/modules on Android devices, so we don't print error if failed to open it.
126 PLOG(DEBUG) << "failed to open file /proc/modules";
127 return result;
128 }
129 LineReader reader(fp);
130 char* line;
131 while ((line = reader.ReadLine()) != nullptr) {
132 // Parse line like: nf_defrag_ipv6 34768 1 nf_conntrack_ipv6, Live 0xffffffffa0fe5000
133 char name[reader.MaxLineSize()];
134 uint64_t addr;
135 uint64_t len;
136 if (sscanf(line, "%s%" PRIu64 "%*u%*s%*s 0x%" PRIx64, name, &len, &addr) == 3) {
137 KernelMmap map;
138 map.name = name;
139 map.start_addr = addr;
140 map.len = len;
141 result.push_back(map);
142 }
143 }
144 bool all_zero = true;
145 for (const auto& map : result) {
146 if (map.start_addr != 0) {
147 all_zero = false;
148 }
149 }
150 if (all_zero) {
151 LOG(DEBUG) << "addresses in /proc/modules are all zero, so ignore kernel modules";
152 return std::vector<KernelMmap>();
153 }
154 return result;
155 }
156
GetAllModuleFiles(const std::string & path,std::unordered_map<std::string,std::string> * module_file_map)157 static void GetAllModuleFiles(const std::string& path,
158 std::unordered_map<std::string, std::string>* module_file_map) {
159 for (const auto& name : GetEntriesInDir(path)) {
160 std::string entry_path = path + "/" + name;
161 if (IsRegularFile(entry_path) && android::base::EndsWith(name, ".ko")) {
162 std::string module_name = name.substr(0, name.size() - 3);
163 std::replace(module_name.begin(), module_name.end(), '-', '_');
164 module_file_map->insert(std::make_pair(module_name, entry_path));
165 } else if (IsDir(entry_path)) {
166 GetAllModuleFiles(entry_path, module_file_map);
167 }
168 }
169 }
170
GetModulesInUse()171 static std::vector<KernelMmap> GetModulesInUse() {
172 std::vector<KernelMmap> module_mmaps = GetLoadedModules();
173 if (module_mmaps.empty()) {
174 return std::vector<KernelMmap>();
175 }
176 std::unordered_map<std::string, std::string> module_file_map;
177 #if defined(__ANDROID__)
178 // Search directories listed in "File locations" section in
179 // https://source.android.com/devices/architecture/kernel/modular-kernels.
180 for (const auto& path : {"/vendor/lib/modules", "/odm/lib/modules", "/lib/modules"}) {
181 GetAllModuleFiles(path, &module_file_map);
182 }
183 #else
184 utsname uname_buf;
185 if (TEMP_FAILURE_RETRY(uname(&uname_buf)) != 0) {
186 PLOG(ERROR) << "uname() failed";
187 return std::vector<KernelMmap>();
188 }
189 std::string linux_version = uname_buf.release;
190 std::string module_dirpath = "/lib/modules/" + linux_version + "/kernel";
191 GetAllModuleFiles(module_dirpath, &module_file_map);
192 #endif
193 for (auto& module : module_mmaps) {
194 auto it = module_file_map.find(module.name);
195 if (it != module_file_map.end()) {
196 module.filepath = it->second;
197 }
198 }
199 return module_mmaps;
200 }
201
GetKernelAndModuleMmaps(KernelMmap * kernel_mmap,std::vector<KernelMmap> * module_mmaps)202 void GetKernelAndModuleMmaps(KernelMmap* kernel_mmap, std::vector<KernelMmap>* module_mmaps) {
203 kernel_mmap->name = DEFAULT_KERNEL_MMAP_NAME;
204 kernel_mmap->start_addr = 0;
205 kernel_mmap->len = std::numeric_limits<uint64_t>::max();
206 kernel_mmap->filepath = kernel_mmap->name;
207 *module_mmaps = GetModulesInUse();
208 for (auto& map : *module_mmaps) {
209 if (map.filepath.empty()) {
210 map.filepath = "[" + map.name + "]";
211 }
212 }
213 }
214
ReadThreadNameAndPid(pid_t tid,std::string * comm,pid_t * pid)215 static bool ReadThreadNameAndPid(pid_t tid, std::string* comm, pid_t* pid) {
216 android::procinfo::ProcessInfo procinfo;
217 if (!android::procinfo::GetProcessInfo(tid, &procinfo)) {
218 return false;
219 }
220 if (comm != nullptr) {
221 *comm = procinfo.name;
222 }
223 if (pid != nullptr) {
224 *pid = procinfo.pid;
225 }
226 return true;
227 }
228
GetThreadsInProcess(pid_t pid)229 std::vector<pid_t> GetThreadsInProcess(pid_t pid) {
230 std::vector<pid_t> result;
231 android::procinfo::GetProcessTids(pid, &result);
232 return result;
233 }
234
IsThreadAlive(pid_t tid)235 bool IsThreadAlive(pid_t tid) {
236 return IsDir(android::base::StringPrintf("/proc/%d", tid));
237 }
238
GetProcessForThread(pid_t tid,pid_t * pid)239 bool GetProcessForThread(pid_t tid, pid_t* pid) {
240 return ReadThreadNameAndPid(tid, nullptr, pid);
241 }
242
GetThreadName(pid_t tid,std::string * name)243 bool GetThreadName(pid_t tid, std::string* name) {
244 return ReadThreadNameAndPid(tid, name, nullptr);
245 }
246
GetAllProcesses()247 std::vector<pid_t> GetAllProcesses() {
248 std::vector<pid_t> result;
249 std::vector<std::string> entries = GetEntriesInDir("/proc");
250 for (const auto& entry : entries) {
251 pid_t pid;
252 if (!android::base::ParseInt(entry.c_str(), &pid, 0)) {
253 continue;
254 }
255 result.push_back(pid);
256 }
257 return result;
258 }
259
GetThreadMmapsInProcess(pid_t pid,std::vector<ThreadMmap> * thread_mmaps)260 bool GetThreadMmapsInProcess(pid_t pid, std::vector<ThreadMmap>* thread_mmaps) {
261 std::string map_file = android::base::StringPrintf("/proc/%d/maps", pid);
262 FILE* fp = fopen(map_file.c_str(), "re");
263 if (fp == nullptr) {
264 PLOG(DEBUG) << "can't open file " << map_file;
265 return false;
266 }
267 thread_mmaps->clear();
268 LineReader reader(fp);
269 char* line;
270 while ((line = reader.ReadLine()) != nullptr) {
271 // Parse line like: 00400000-00409000 r-xp 00000000 fc:00 426998 /usr/lib/gvfs/gvfsd-http
272 uint64_t start_addr, end_addr, pgoff;
273 char type[reader.MaxLineSize()];
274 char execname[reader.MaxLineSize()];
275 strcpy(execname, "");
276 if (sscanf(line, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %*x:%*x %*u %s\n", &start_addr,
277 &end_addr, type, &pgoff, execname) < 4) {
278 continue;
279 }
280 if (strcmp(execname, "") == 0) {
281 strcpy(execname, DEFAULT_EXECNAME_FOR_THREAD_MMAP);
282 }
283 ThreadMmap thread;
284 thread.start_addr = start_addr;
285 thread.len = end_addr - start_addr;
286 thread.pgoff = pgoff;
287 thread.name = execname;
288 thread.executable = (type[2] == 'x');
289 thread_mmaps->push_back(thread);
290 }
291 return true;
292 }
293
GetKernelBuildId(BuildId * build_id)294 bool GetKernelBuildId(BuildId* build_id) {
295 ElfStatus result = GetBuildIdFromNoteFile("/sys/kernel/notes", build_id);
296 if (result != ElfStatus::NO_ERROR) {
297 LOG(DEBUG) << "failed to read /sys/kernel/notes: " << result;
298 }
299 return result == ElfStatus::NO_ERROR;
300 }
301
GetModuleBuildId(const std::string & module_name,BuildId * build_id)302 bool GetModuleBuildId(const std::string& module_name, BuildId* build_id) {
303 std::string notefile = "/sys/module/" + module_name + "/notes/.note.gnu.build-id";
304 return GetBuildIdFromNoteFile(notefile, build_id);
305 }
306
GetValidThreadsFromThreadString(const std::string & tid_str,std::set<pid_t> * tid_set)307 bool GetValidThreadsFromThreadString(const std::string& tid_str, std::set<pid_t>* tid_set) {
308 std::vector<std::string> strs = android::base::Split(tid_str, ",");
309 for (const auto& s : strs) {
310 int tid;
311 if (!android::base::ParseInt(s.c_str(), &tid, 0)) {
312 LOG(ERROR) << "Invalid tid '" << s << "'";
313 return false;
314 }
315 if (!IsDir(android::base::StringPrintf("/proc/%d", tid))) {
316 LOG(ERROR) << "Non existing thread '" << tid << "'";
317 return false;
318 }
319 tid_set->insert(tid);
320 }
321 return true;
322 }
323
324 /*
325 * perf event paranoia level:
326 * -1 - not paranoid at all
327 * 0 - disallow raw tracepoint access for unpriv
328 * 1 - disallow cpu events for unpriv
329 * 2 - disallow kernel profiling for unpriv
330 * 3 - disallow user profiling for unpriv
331 */
ReadPerfEventParanoid(int * value)332 static bool ReadPerfEventParanoid(int* value) {
333 std::string s;
334 if (!android::base::ReadFileToString("/proc/sys/kernel/perf_event_paranoid", &s)) {
335 PLOG(DEBUG) << "failed to read /proc/sys/kernel/perf_event_paranoid";
336 return false;
337 }
338 s = android::base::Trim(s);
339 if (!android::base::ParseInt(s.c_str(), value)) {
340 PLOG(ERROR) << "failed to parse /proc/sys/kernel/perf_event_paranoid: " << s;
341 return false;
342 }
343 return true;
344 }
345
CanRecordRawData()346 bool CanRecordRawData() {
347 int value;
348 return IsRoot() || (ReadPerfEventParanoid(&value) && value == -1);
349 }
350
GetLimitLevelDescription(int limit_level)351 static const char* GetLimitLevelDescription(int limit_level) {
352 switch (limit_level) {
353 case -1: return "unlimited";
354 case 0: return "disallowing raw tracepoint access for unpriv";
355 case 1: return "disallowing cpu events for unpriv";
356 case 2: return "disallowing kernel profiling for unpriv";
357 case 3: return "disallowing user profiling for unpriv";
358 default: return "unknown level";
359 }
360 }
361
CheckPerfEventLimit()362 bool CheckPerfEventLimit() {
363 // Root is not limited by /proc/sys/kernel/perf_event_paranoid. However, the monitored threads
364 // may create child processes not running as root. To make sure the child processes have
365 // enough permission to create inherited tracepoint events, write -1 to perf_event_paranoid.
366 // See http://b/62230699.
367 if (IsRoot() && android::base::WriteStringToFile("-1", "/proc/sys/kernel/perf_event_paranoid")) {
368 return true;
369 }
370 int limit_level;
371 bool can_read_paranoid = ReadPerfEventParanoid(&limit_level);
372 if (can_read_paranoid && limit_level <= 1) {
373 return true;
374 }
375 #if defined(__ANDROID__)
376 const std::string prop_name = "security.perf_harden";
377 std::string prop_value = android::base::GetProperty(prop_name, "");
378 if (prop_value.empty()) {
379 // can't do anything if there is no such property.
380 return true;
381 }
382 if (prop_value == "0") {
383 return true;
384 }
385 // Try to enable perf_event_paranoid by setprop security.perf_harden=0.
386 if (android::base::SetProperty(prop_name, "0")) {
387 sleep(1);
388 if (can_read_paranoid && ReadPerfEventParanoid(&limit_level) && limit_level <= 1) {
389 return true;
390 }
391 if (android::base::GetProperty(prop_name, "") == "0") {
392 return true;
393 }
394 }
395 if (can_read_paranoid) {
396 LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level
397 << ", " << GetLimitLevelDescription(limit_level) << ".";
398 }
399 LOG(WARNING) << "Try using `adb shell setprop security.perf_harden 0` to allow profiling.";
400 return false;
401 #else
402 if (can_read_paranoid) {
403 LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level
404 << ", " << GetLimitLevelDescription(limit_level) << ".";
405 return false;
406 }
407 #endif
408 return true;
409 }
410
GetMaxSampleFrequency(uint64_t * max_sample_freq)411 bool GetMaxSampleFrequency(uint64_t* max_sample_freq) {
412 std::string s;
413 if (!android::base::ReadFileToString("/proc/sys/kernel/perf_event_max_sample_rate", &s)) {
414 PLOG(DEBUG) << "failed to read /proc/sys/kernel/perf_event_max_sample_rate";
415 return false;
416 }
417 s = android::base::Trim(s);
418 if (!android::base::ParseUint(s.c_str(), max_sample_freq)) {
419 LOG(ERROR) << "failed to parse /proc/sys/kernel/perf_event_max_sample_rate: " << s;
420 return false;
421 }
422 return true;
423 }
424
CheckKernelSymbolAddresses()425 bool CheckKernelSymbolAddresses() {
426 const std::string kptr_restrict_file = "/proc/sys/kernel/kptr_restrict";
427 std::string s;
428 if (!android::base::ReadFileToString(kptr_restrict_file, &s)) {
429 PLOG(DEBUG) << "failed to read " << kptr_restrict_file;
430 return false;
431 }
432 s = android::base::Trim(s);
433 int value;
434 if (!android::base::ParseInt(s.c_str(), &value)) {
435 LOG(ERROR) << "failed to parse " << kptr_restrict_file << ": " << s;
436 return false;
437 }
438 // Accessible to everyone?
439 if (value == 0) {
440 return true;
441 }
442 // Accessible to root?
443 if (value == 1 && IsRoot()) {
444 return true;
445 }
446 // Can we make it accessible to us?
447 if (IsRoot() && android::base::WriteStringToFile("1", kptr_restrict_file)) {
448 return true;
449 }
450 LOG(WARNING) << "Access to kernel symbol addresses is restricted. If "
451 << "possible, please do `echo 0 >/proc/sys/kernel/kptr_restrict` "
452 << "to fix this.";
453 return false;
454 }
455
GetMachineArch()456 ArchType GetMachineArch() {
457 utsname uname_buf;
458 if (TEMP_FAILURE_RETRY(uname(&uname_buf)) != 0) {
459 PLOG(WARNING) << "uname() failed";
460 return GetBuildArch();
461 }
462 ArchType arch = GetArchType(uname_buf.machine);
463 if (arch != ARCH_UNSUPPORTED) {
464 return arch;
465 }
466 return GetBuildArch();
467 }
468
PrepareVdsoFile()469 void PrepareVdsoFile() {
470 // vdso is an elf file in memory loaded in each process's user space by the kernel. To read
471 // symbols from it and unwind through it, we need to dump it into a file in storage.
472 // It doesn't affect much when failed to prepare vdso file, so there is no need to return values.
473 std::vector<ThreadMmap> thread_mmaps;
474 if (!GetThreadMmapsInProcess(getpid(), &thread_mmaps)) {
475 return;
476 }
477 const ThreadMmap* vdso_map = nullptr;
478 for (const auto& map : thread_mmaps) {
479 if (map.name == "[vdso]") {
480 vdso_map = ↦
481 break;
482 }
483 }
484 if (vdso_map == nullptr) {
485 return;
486 }
487 std::string s(vdso_map->len, '\0');
488 memcpy(&s[0], reinterpret_cast<void*>(static_cast<uintptr_t>(vdso_map->start_addr)),
489 vdso_map->len);
490 std::unique_ptr<TemporaryFile> tmpfile = ScopedTempFiles::CreateTempFile();
491 if (!android::base::WriteStringToFd(s, tmpfile->release())) {
492 return;
493 }
494 Dso::SetVdsoFile(tmpfile->path, sizeof(size_t) == sizeof(uint64_t));
495 }
496
HasOpenedAppApkFile(int pid)497 static bool HasOpenedAppApkFile(int pid) {
498 std::string fd_path = "/proc/" + std::to_string(pid) + "/fd/";
499 std::vector<std::string> files = GetEntriesInDir(fd_path);
500 for (const auto& file : files) {
501 std::string real_path;
502 if (!android::base::Readlink(fd_path + file, &real_path)) {
503 continue;
504 }
505 if (real_path.find("app") != std::string::npos && real_path.find(".apk") != std::string::npos) {
506 return true;
507 }
508 }
509 return false;
510 }
511
WaitForAppProcesses(const std::string & package_name)512 std::set<pid_t> WaitForAppProcesses(const std::string& package_name) {
513 std::set<pid_t> result;
514 size_t loop_count = 0;
515 while (true) {
516 std::vector<pid_t> pids = GetAllProcesses();
517 for (pid_t pid : pids) {
518 std::string cmdline;
519 if (!android::base::ReadFileToString("/proc/" + std::to_string(pid) + "/cmdline", &cmdline)) {
520 // Maybe we don't have permission to read it.
521 continue;
522 }
523 std::string process_name = android::base::Basename(cmdline);
524 // The app may have multiple processes, with process name like
525 // com.google.android.googlequicksearchbox:search.
526 size_t split_pos = process_name.find(':');
527 if (split_pos != std::string::npos) {
528 process_name = process_name.substr(0, split_pos);
529 }
530 if (process_name != package_name) {
531 continue;
532 }
533 // If a debuggable app with wrap.sh runs on Android O, the app will be started with
534 // logwrapper as below:
535 // 1. Zygote forks a child process, rename it to package_name.
536 // 2. The child process execute sh, which starts a child process running
537 // /system/bin/logwrapper.
538 // 3. logwrapper starts a child process running sh, which interprets wrap.sh.
539 // 4. wrap.sh starts a child process running the app.
540 // The problem here is we want to profile the process started in step 4, but sometimes we
541 // run into the process started in step 1. To solve it, we can check if the process has
542 // opened an apk file in some app dirs.
543 if (!HasOpenedAppApkFile(pid)) {
544 continue;
545 }
546 if (loop_count > 0u) {
547 LOG(INFO) << "Got process " << pid << " for package " << package_name;
548 }
549 result.insert(pid);
550 }
551 if (!result.empty()) {
552 return result;
553 }
554 if (++loop_count == 1u) {
555 LOG(INFO) << "Waiting for process of app " << package_name;
556 }
557 usleep(1000);
558 }
559 }
560
561 class ScopedFile {
562 public:
ScopedFile(const std::string & filepath,const std::string & app_package_name="")563 ScopedFile(const std::string& filepath, const std::string& app_package_name = "")
564 : filepath_(filepath), app_package_name_(app_package_name) {}
565
~ScopedFile()566 ~ScopedFile() {
567 if (app_package_name_.empty()) {
568 unlink(filepath_.c_str());
569 } else {
570 Workload::RunCmd({"run-as", app_package_name_, "rm", "-rf", filepath_});
571 }
572 }
573
574 private:
575 std::string filepath_;
576 std::string app_package_name_;
577 };
578
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)579 bool RunInAppContext(const std::string& app_package_name, const std::string& cmd,
580 const std::vector<std::string>& args, size_t workload_args_size,
581 const std::string& output_filepath, bool need_tracepoint_events) {
582 // 1. Test if the package exists.
583 if (!Workload::RunCmd({"run-as", app_package_name, "echo", ">/dev/null"}, false)) {
584 LOG(ERROR) << "Package " << app_package_name << " doesn't exist or isn't debuggable.";
585 return false;
586 }
587
588 // 2. Copy simpleperf binary to the package. Create tracepoint_file if needed.
589 std::string simpleperf_path;
590 if (!android::base::Readlink("/proc/self/exe", &simpleperf_path)) {
591 PLOG(ERROR) << "ReadLink failed";
592 return false;
593 }
594 if (!Workload::RunCmd({"run-as", app_package_name, "cp", simpleperf_path, "simpleperf"})) {
595 return false;
596 }
597 ScopedFile scoped_simpleperf("simpleperf", app_package_name);
598 std::unique_ptr<ScopedFile> scoped_tracepoint_file;
599 const std::string tracepoint_file = "/data/local/tmp/tracepoint_events";
600 if (need_tracepoint_events) {
601 // Since we can't read tracepoint events from tracefs in app's context, we need to prepare
602 // them in tracepoint_file in shell's context, and pass the path of tracepoint_file to the
603 // child process using --tracepoint-events option.
604 if (!android::base::WriteStringToFile(GetTracepointEvents(), tracepoint_file)) {
605 PLOG(ERROR) << "Failed to store tracepoint events";
606 return false;
607 }
608 scoped_tracepoint_file.reset(new ScopedFile(tracepoint_file));
609 }
610
611 // 3. Prepare to start child process to profile.
612 std::string output_basename = output_filepath.empty() ? "" :
613 android::base::Basename(output_filepath);
614 std::vector<std::string> new_args =
615 {"run-as", app_package_name, "./simpleperf", cmd, "--in-app", "--log", GetLogSeverityName()};
616 if (need_tracepoint_events) {
617 new_args.push_back("--tracepoint-events");
618 new_args.push_back(tracepoint_file);
619 }
620 for (size_t i = 0; i < args.size(); ++i) {
621 if (i >= args.size() - workload_args_size || args[i] != "-o") {
622 new_args.push_back(args[i]);
623 } else {
624 new_args.push_back(args[i++]);
625 new_args.push_back(output_basename);
626 }
627 }
628 std::unique_ptr<Workload> workload = Workload::CreateWorkload(new_args);
629 if (!workload) {
630 return false;
631 }
632
633 IOEventLoop loop;
634 bool need_to_kill_child = false;
635 if (!loop.AddSignalEvents({SIGINT, SIGTERM, SIGHUP},
636 [&]() { need_to_kill_child = true; return loop.ExitLoop(); })) {
637 return false;
638 }
639 if (!loop.AddSignalEvent(SIGCHLD, [&]() { return loop.ExitLoop(); })) {
640 return false;
641 }
642
643 // 4. Create child process to run run-as, and wait for the child process.
644 if (!workload->Start()) {
645 return false;
646 }
647 if (!loop.RunLoop()) {
648 return false;
649 }
650 if (need_to_kill_child) {
651 // The child process can exit before we kill it, so don't report kill errors.
652 Workload::RunCmd({"run-as", app_package_name, "pkill", "simpleperf"}, false);
653 }
654 int exit_code;
655 if (!workload->WaitChildProcess(&exit_code) || exit_code != 0) {
656 return false;
657 }
658
659 // 5. If there is any output file, copy it from the app's directory.
660 if (!output_filepath.empty()) {
661 if (!Workload::RunCmd({"run-as", app_package_name, "cat", output_basename,
662 ">" + output_filepath})) {
663 return false;
664 }
665 if (!Workload::RunCmd({"run-as", app_package_name, "rm", output_basename})) {
666 return false;
667 }
668 }
669 return true;
670 }
671
672 static std::string default_package_name;
673
SetDefaultAppPackageName(const std::string & package_name)674 void SetDefaultAppPackageName(const std::string& package_name) {
675 default_package_name = package_name;
676 }
677
GetDefaultAppPackageName()678 const std::string& GetDefaultAppPackageName() {
679 return default_package_name;
680 }
681
AllowMoreOpenedFiles()682 void AllowMoreOpenedFiles() {
683 // On Android <= O, the hard limit is 4096, and the soft limit is 1024.
684 // On Android >= P, both the hard and soft limit are 32768.
685 rlimit limit;
686 if (getrlimit(RLIMIT_NOFILE, &limit) == 0) {
687 limit.rlim_cur = limit.rlim_max;
688 setrlimit(RLIMIT_NOFILE, &limit);
689 }
690 }
691
692 std::string ScopedTempFiles::tmp_dir_;
693 std::vector<std::string> ScopedTempFiles::files_to_delete_;
694
ScopedTempFiles(const std::string & tmp_dir)695 ScopedTempFiles::ScopedTempFiles(const std::string& tmp_dir) {
696 CHECK(tmp_dir_.empty()); // No other ScopedTempFiles.
697 tmp_dir_ = tmp_dir;
698 }
699
~ScopedTempFiles()700 ScopedTempFiles::~ScopedTempFiles() {
701 tmp_dir_.clear();
702 for (auto& file : files_to_delete_) {
703 unlink(file.c_str());
704 }
705 files_to_delete_.clear();
706 }
707
CreateTempFile(bool delete_in_destructor)708 std::unique_ptr<TemporaryFile> ScopedTempFiles::CreateTempFile(bool delete_in_destructor) {
709 CHECK(!tmp_dir_.empty());
710 std::unique_ptr<TemporaryFile> tmp_file(new TemporaryFile(tmp_dir_));
711 CHECK_NE(tmp_file->fd, -1);
712 if (delete_in_destructor) {
713 files_to_delete_.push_back(tmp_file->path);
714 }
715 return tmp_file;
716 }
717
SignalIsIgnored(int signo)718 bool SignalIsIgnored(int signo) {
719 struct sigaction act;
720 if (sigaction(signo, nullptr, &act) != 0) {
721 PLOG(FATAL) << "failed to query signal handler for signal " << signo;
722 }
723
724 if ((act.sa_flags & SA_SIGINFO)) {
725 return false;
726 }
727
728 return act.sa_handler == SIG_IGN;
729 }
730