• 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 #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 = &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