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