• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = &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