1/*
2**
3** Copyright 2015, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <assert.h>
19#include <dirent.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <signal.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28#include <sys/wait.h>
29#include <time.h>
30#include <unistd.h>
31#include <string>
32#include <sstream>
33#include <map>
34#include <set>
35#include <cctype>
36
37#include <android-base/file.h>
38#include <android-base/stringprintf.h>
39#include <cutils/properties.h>
40
41#include "perfprofdcore.h"
42#include "perfprofdutils.h"
43#include "perf_data_converter.h"
44#include "cpuconfig.h"
45#include "configreader.h"
46
47//
48// Perf profiling daemon -- collects system-wide profiles using
49//
50//       simpleperf record -a
51//
52// and encodes them so that they can be uploaded by a separate service.
53//
54
55//......................................................................
56
57//
58// Output file from 'perf record'.
59//
60#define PERF_OUTPUT "perf.data"
61
62//
63// This enum holds the results of the "should we profile" configuration check.
64//
65typedef enum {
66
67  // All systems go for profile collection.
68  DO_COLLECT_PROFILE,
69
70  // The selected configuration directory doesn't exist.
71  DONT_PROFILE_MISSING_CONFIG_DIR,
72
73  // Destination directory does not contain the semaphore file that
74  // the perf profile uploading service creates when it determines
75  // that the user has opted "in" for usage data collection. No
76  // semaphore -> no user approval -> no profiling.
77  DONT_PROFILE_MISSING_SEMAPHORE,
78
79  // No perf executable present
80  DONT_PROFILE_MISSING_PERF_EXECUTABLE,
81
82  // We're running in the emulator, perf won't be able to do much
83  DONT_PROFILE_RUNNING_IN_EMULATOR
84
85} CKPROFILE_RESULT;
86
87//
88// Are we running in the emulator? If so, stub out profile collection
89// Starts as uninitialized (-1), then set to 1 or 0 at init time.
90//
91static int running_in_emulator = -1;
92
93//
94// Is this a debug build ('userdebug' or 'eng')?
95// Starts as uninitialized (-1), then set to 1 or 0 at init time.
96//
97static int is_debug_build = -1;
98
99//
100// Path to the perf file to convert and exit? Empty value is the default, daemon mode.
101//
102static std::string perf_file_to_convert = "";
103
104//
105// Random number generator seed (set at startup time).
106//
107static unsigned short random_seed[3];
108
109//
110// SIGHUP handler. Sending SIGHUP to the daemon can be used to break it
111// out of a sleep() call so as to trigger a new collection (debugging)
112//
113static void sig_hup(int /* signum */)
114{
115  W_ALOGW("SIGHUP received");
116}
117
118//
119// Parse command line args. Currently supported flags:
120// *  "-c PATH" sets the path of the config file to PATH.
121// *  "-x PATH" reads PATH as a perf data file and saves it as a file in
122//    perf_profile.proto format. ".encoded" suffix is appended to PATH to form
123//    the output file path.
124//
125static void parse_args(int argc, char** argv)
126{
127  int ac;
128
129  for (ac = 1; ac < argc; ++ac) {
130    if (!strcmp(argv[ac], "-c")) {
131      if (ac >= argc-1) {
132        W_ALOGE("malformed command line: -c option requires argument)");
133        continue;
134      }
135      ConfigReader::setConfigFilePath(argv[ac+1]);
136      ++ac;
137    } else if (!strcmp(argv[ac], "-x")) {
138      if (ac >= argc-1) {
139        W_ALOGE("malformed command line: -x option requires argument)");
140        continue;
141      }
142      perf_file_to_convert = argv[ac+1];
143      ++ac;
144    } else {
145      W_ALOGE("malformed command line: unknown option or arg %s)", argv[ac]);
146      continue;
147    }
148  }
149}
150
151//
152// Convert a CKPROFILE_RESULT to a string
153//
154const char *ckprofile_result_to_string(CKPROFILE_RESULT result)
155{
156  switch (result) {
157    case DO_COLLECT_PROFILE:
158      return "DO_COLLECT_PROFILE";
159    case DONT_PROFILE_MISSING_CONFIG_DIR:
160      return "missing config directory";
161    case DONT_PROFILE_MISSING_SEMAPHORE:
162      return "missing semaphore file";
163    case DONT_PROFILE_MISSING_PERF_EXECUTABLE:
164      return "missing 'perf' executable";
165    case DONT_PROFILE_RUNNING_IN_EMULATOR:
166      return "running in emulator";
167    default: return "unknown";
168  }
169  return "notreached";
170}
171
172//
173// Convert a PROFILE_RESULT to a string
174//
175const char *profile_result_to_string(PROFILE_RESULT result)
176{
177  switch(result) {
178    case OK_PROFILE_COLLECTION:
179      return "profile collection succeeded";
180    case ERR_FORK_FAILED:
181      return "fork() system call failed";
182    case ERR_PERF_RECORD_FAILED:
183      return "perf record returned bad exit status";
184    case ERR_PERF_ENCODE_FAILED:
185      return "failure encoding perf.data to protobuf";
186    case ERR_OPEN_ENCODED_FILE_FAILED:
187      return "failed to open encoded perf file";
188    case ERR_WRITE_ENCODED_FILE_FAILED:
189      return "write to encoded perf file failed";
190    default: return "unknown";
191  }
192  return "notreached";
193}
194
195//
196// Check to see whether we should perform a profile collection
197//
198static CKPROFILE_RESULT check_profiling_enabled(ConfigReader &config)
199{
200  //
201  // Profile collection in the emulator doesn't make sense
202  //
203  assert(running_in_emulator != -1);
204  if (running_in_emulator) {
205    return DONT_PROFILE_RUNNING_IN_EMULATOR;
206  }
207
208  //
209  // Check for existence of semaphore file in config directory
210  //
211  if (access(config.getStringValue("config_directory").c_str(), F_OK) == -1) {
212    W_ALOGW("unable to open config directory %s: (%s)",
213            config.getStringValue("config_directory").c_str(), strerror(errno));
214    return DONT_PROFILE_MISSING_CONFIG_DIR;
215  }
216
217
218  // Check for existence of semaphore file
219  std::string semaphore_filepath = config.getStringValue("config_directory")
220                                   + "/" + SEMAPHORE_FILENAME;
221  if (access(semaphore_filepath.c_str(), F_OK) == -1) {
222    return DONT_PROFILE_MISSING_SEMAPHORE;
223  }
224
225  // Check for existence of simpleperf/perf executable
226  std::string pp = config.getStringValue("perf_path");
227  if (access(pp.c_str(), R_OK|X_OK) == -1) {
228    W_ALOGW("unable to access/execute %s", pp.c_str());
229    return DONT_PROFILE_MISSING_PERF_EXECUTABLE;
230  }
231
232  //
233  // We are good to go
234  //
235  return DO_COLLECT_PROFILE;
236}
237
238bool get_booting()
239{
240  char propBuf[PROPERTY_VALUE_MAX];
241  propBuf[0] = '\0';
242  property_get("sys.boot_completed", propBuf, "");
243  return (propBuf[0] != '1');
244}
245
246//
247// Constructor takes a timeout (in seconds) and a child pid; If an
248// alarm set for the specified number of seconds triggers, then a
249// SIGKILL is sent to the child. Destructor resets alarm. Example:
250//
251//       pid_t child_pid = ...;
252//       { AlarmHelper h(10, child_pid);
253//         ... = read_from_child(child_pid, ...);
254//       }
255//
256// NB: this helper is not re-entrant-- avoid nested use or
257// use by multiple threads
258//
259class AlarmHelper {
260 public:
261  AlarmHelper(unsigned num_seconds, pid_t child)
262  {
263    struct sigaction sigact;
264    assert(child);
265    assert(child_ == 0);
266    memset(&sigact, 0, sizeof(sigact));
267    sigact.sa_sigaction = handler;
268    sigaction(SIGALRM, &sigact, &oldsigact_);
269    child_ = child;
270    alarm(num_seconds);
271  }
272  ~AlarmHelper()
273  {
274    alarm(0);
275    child_ = 0;
276    sigaction(SIGALRM, &oldsigact_, NULL);
277  }
278  static void handler(int, siginfo_t *, void *);
279
280 private:
281  struct sigaction oldsigact_;
282  static pid_t child_;
283};
284
285pid_t AlarmHelper::child_;
286
287void AlarmHelper::handler(int, siginfo_t *, void *)
288{
289  W_ALOGW("SIGALRM timeout");
290  kill(child_, SIGKILL);
291}
292
293//
294// This implementation invokes "dumpsys media.camera" and inspects the
295// output to determine if any camera clients are active. NB: this is
296// currently disable (via config option) until the selinux issues can
297// be sorted out. Another possible implementation (not yet attempted)
298// would be to use the binder to call into the native camera service
299// via "ICameraService".
300//
301bool get_camera_active()
302{
303  int pipefds[2];
304  if (pipe2(pipefds, O_CLOEXEC) != 0) {
305    W_ALOGE("pipe2() failed (%s)", strerror(errno));
306    return false;
307  }
308  pid_t pid = fork();
309  if (pid == -1) {
310    W_ALOGE("fork() failed (%s)", strerror(errno));
311    close(pipefds[0]);
312    close(pipefds[1]);
313    return false;
314  } else if (pid == 0) {
315    // child
316    close(pipefds[0]);
317    dup2(pipefds[1], fileno(stderr));
318    dup2(pipefds[1], fileno(stdout));
319    const char *argv[10];
320    unsigned slot = 0;
321    argv[slot++] = "/system/bin/dumpsys";
322    argv[slot++] = "media.camera";
323    argv[slot++] = nullptr;
324    execvp(argv[0], (char * const *)argv);
325    W_ALOGE("execvp() failed (%s)", strerror(errno));
326    return false;
327  }
328  // parent
329  AlarmHelper helper(10, pid);
330  close(pipefds[1]);
331
332  // read output
333  bool have_cam = false;
334  bool have_clients = true;
335  std::string dump_output;
336  bool result = android::base::ReadFdToString(pipefds[0], &dump_output);
337  close(pipefds[0]);
338  if (result) {
339    std::stringstream ss(dump_output);
340    std::string line;
341    while (std::getline(ss,line,'\n')) {
342      if (line.find("Camera module API version:") !=
343          std::string::npos) {
344        have_cam = true;
345      }
346      if (line.find("No camera module available") !=
347          std::string::npos ||
348          line.find("No active camera clients yet") !=
349          std::string::npos) {
350        have_clients = false;
351      }
352    }
353  }
354
355  // reap child (no zombies please)
356  int st = 0;
357  TEMP_FAILURE_RETRY(waitpid(pid, &st, 0));
358  return have_cam && have_clients;
359}
360
361bool get_charging()
362{
363  std::string psdir("/sys/class/power_supply");
364  DIR* dir = opendir(psdir.c_str());
365  if (dir == NULL) {
366    W_ALOGE("Failed to open dir %s (%s)", psdir.c_str(), strerror(errno));
367    return false;
368  }
369  struct dirent* e;
370  bool result = false;
371  while ((e = readdir(dir)) != 0) {
372    if (e->d_name[0] != '.') {
373      std::string online_path = psdir + "/" + e->d_name + "/online";
374      std::string contents;
375      int value = 0;
376      if (android::base::ReadFileToString(online_path.c_str(), &contents) &&
377          sscanf(contents.c_str(), "%d", &value) == 1) {
378        if (value) {
379          result = true;
380          break;
381        }
382      }
383    }
384  }
385  closedir(dir);
386  return result;
387}
388
389bool postprocess_proc_stat_contents(const std::string &pscontents,
390                                    long unsigned *idleticks,
391                                    long unsigned *remainingticks)
392{
393  long unsigned usertime, nicetime, systime, idletime, iowaittime;
394  long unsigned irqtime, softirqtime;
395
396  int rc = sscanf(pscontents.c_str(), "cpu  %lu %lu %lu %lu %lu %lu %lu",
397                  &usertime, &nicetime, &systime, &idletime,
398                  &iowaittime, &irqtime, &softirqtime);
399  if (rc != 7) {
400    return false;
401  }
402  *idleticks = idletime;
403  *remainingticks = usertime + nicetime + systime + iowaittime + irqtime + softirqtime;
404  return true;
405}
406
407unsigned collect_cpu_utilization()
408{
409  std::string contents;
410  long unsigned idle[2];
411  long unsigned busy[2];
412  for (unsigned iter = 0; iter < 2; ++iter) {
413    if (!android::base::ReadFileToString("/proc/stat", &contents)) {
414      return 0;
415    }
416    if (!postprocess_proc_stat_contents(contents, &idle[iter], &busy[iter])) {
417      return 0;
418    }
419    if (iter == 0) {
420      sleep(1);
421    }
422  }
423  long unsigned total_delta = (idle[1] + busy[1]) - (idle[0] + busy[0]);
424  long unsigned busy_delta = busy[1] - busy[0];
425  return busy_delta * 100 / total_delta;
426}
427
428static void annotate_encoded_perf_profile(wireless_android_play_playlog::AndroidPerfProfile *profile,
429                                          const ConfigReader &config,
430                                          unsigned cpu_utilization)
431{
432  //
433  // Incorporate cpu utilization (collected prior to perf run)
434  //
435  if (config.getUnsignedValue("collect_cpu_utilization")) {
436    profile->set_cpu_utilization(cpu_utilization);
437  }
438
439  //
440  // Load average as reported by the kernel
441  //
442  std::string load;
443  double fload = 0.0;
444  if (android::base::ReadFileToString("/proc/loadavg", &load) &&
445      sscanf(load.c_str(), "%lf", &fload) == 1) {
446    int iload = static_cast<int>(fload * 100.0);
447    profile->set_sys_load_average(iload);
448  } else {
449    W_ALOGE("Failed to read or scan /proc/loadavg (%s)", strerror(errno));
450  }
451
452  //
453  // Device still booting? Camera in use? Plugged into charger?
454  //
455  bool is_booting = get_booting();
456  if (config.getUnsignedValue("collect_booting")) {
457    profile->set_booting(is_booting);
458  }
459  if (config.getUnsignedValue("collect_camera_active")) {
460    profile->set_camera_active(is_booting ? false : get_camera_active());
461  }
462  if (config.getUnsignedValue("collect_charging_state")) {
463    profile->set_on_charger(get_charging());
464  }
465
466  //
467  // Examine the contents of wake_unlock to determine whether the
468  // device display is on or off. NB: is this really the only way to
469  // determine this info?
470  //
471  std::string disp;
472  if (android::base::ReadFileToString("/sys/power/wake_unlock", &disp)) {
473    bool ison = (strstr(disp.c_str(), "PowerManagerService.Display") == 0);
474    profile->set_display_on(ison);
475  } else {
476    W_ALOGE("Failed to read /sys/power/wake_unlock (%s)", strerror(errno));
477  }
478}
479
480inline char* string_as_array(std::string* str) {
481  return str->empty() ? NULL : &*str->begin();
482}
483
484PROFILE_RESULT encode_to_proto(const std::string &data_file_path,
485                               const char *encoded_file_path,
486                               const ConfigReader &config,
487                               unsigned cpu_utilization)
488{
489  //
490  // Open and read perf.data file
491  //
492  const wireless_android_play_playlog::AndroidPerfProfile &encodedProfile =
493      wireless_android_logging_awp::RawPerfDataToAndroidPerfProfile(data_file_path);
494
495  //
496  // Issue error if no samples
497  //
498  if (encodedProfile.programs().size() == 0) {
499    return ERR_PERF_ENCODE_FAILED;
500  }
501
502  // All of the info in 'encodedProfile' is derived from the perf.data file;
503  // here we tack display status, cpu utilization, system load, etc.
504  wireless_android_play_playlog::AndroidPerfProfile &prof =
505      const_cast<wireless_android_play_playlog::AndroidPerfProfile&>
506      (encodedProfile);
507  annotate_encoded_perf_profile(&prof, config, cpu_utilization);
508
509  //
510  // Serialize protobuf to array
511  //
512  int size = encodedProfile.ByteSize();
513  std::string data;
514  data.resize(size);
515  ::google::protobuf::uint8* dtarget =
516        reinterpret_cast<::google::protobuf::uint8*>(string_as_array(&data));
517  encodedProfile.SerializeWithCachedSizesToArray(dtarget);
518
519  //
520  // Open file and write encoded data to it
521  //
522  FILE *fp = fopen(encoded_file_path, "w");
523  if (!fp) {
524    return ERR_OPEN_ENCODED_FILE_FAILED;
525  }
526  size_t fsiz = size;
527  if (fwrite(dtarget, fsiz, 1, fp) != 1) {
528    fclose(fp);
529    return ERR_WRITE_ENCODED_FILE_FAILED;
530  }
531  fclose(fp);
532  chmod(encoded_file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
533
534  return OK_PROFILE_COLLECTION;
535}
536
537//
538// Invoke "perf record". Return value is OK_PROFILE_COLLECTION for
539// success, or some other error code if something went wrong.
540//
541static PROFILE_RESULT invoke_perf(const std::string &perf_path,
542                                  unsigned sampling_period,
543                                  const char *stack_profile_opt,
544                                  unsigned duration,
545                                  const std::string &data_file_path,
546                                  const std::string &perf_stderr_path)
547{
548  pid_t pid = fork();
549
550  if (pid == -1) {
551    return ERR_FORK_FAILED;
552  }
553
554  if (pid == 0) {
555    // child
556
557    // Open file to receive stderr/stdout from perf
558    FILE *efp = fopen(perf_stderr_path.c_str(), "w");
559    if (efp) {
560      dup2(fileno(efp), STDERR_FILENO);
561      dup2(fileno(efp), STDOUT_FILENO);
562    } else {
563      W_ALOGW("unable to open %s for writing", perf_stderr_path.c_str());
564    }
565
566    // marshall arguments
567    constexpr unsigned max_args = 13;
568    const char *argv[max_args];
569    unsigned slot = 0;
570    argv[slot++] = perf_path.c_str();
571    argv[slot++] = "record";
572
573    // -o perf.data
574    argv[slot++] = "-o";
575    argv[slot++] = data_file_path.c_str();
576
577    // -c N
578    argv[slot++] = "-c";
579    std::string p_str = android::base::StringPrintf("%u", sampling_period);
580    argv[slot++] = p_str.c_str();
581
582    // -g if desired
583    if (stack_profile_opt)
584      argv[slot++] = stack_profile_opt;
585
586    // system wide profiling
587    argv[slot++] = "-a";
588
589    // no need for kernel symbols
590    argv[slot++] = "--no-dump-kernel-symbols";
591
592    // sleep <duration>
593    argv[slot++] = "/system/bin/sleep";
594    std::string d_str = android::base::StringPrintf("%u", duration);
595    argv[slot++] = d_str.c_str();
596
597    // terminator
598    argv[slot++] = nullptr;
599    assert(slot < max_args);
600
601    // record the final command line in the error output file for
602    // posterity/debugging purposes
603    fprintf(stderr, "perf invocation (pid=%d):\n", getpid());
604    for (unsigned i = 0; argv[i] != nullptr; ++i) {
605      fprintf(stderr, "%s%s", i ? " " : "", argv[i]);
606    }
607    fprintf(stderr, "\n");
608
609    // exec
610    execvp(argv[0], (char * const *)argv);
611    fprintf(stderr, "exec failed: %s\n", strerror(errno));
612    exit(1);
613
614  } else {
615    // parent
616    int st = 0;
617    pid_t reaped = TEMP_FAILURE_RETRY(waitpid(pid, &st, 0));
618
619    if (reaped == -1) {
620      W_ALOGW("waitpid failed: %s", strerror(errno));
621    } else if (WIFSIGNALED(st)) {
622      W_ALOGW("perf killed by signal %d", WTERMSIG(st));
623    } else if (WEXITSTATUS(st) != 0) {
624      W_ALOGW("perf bad exit status %d", WEXITSTATUS(st));
625    } else {
626      return OK_PROFILE_COLLECTION;
627    }
628  }
629
630  return ERR_PERF_RECORD_FAILED;
631}
632
633//
634// Remove all files in the destination directory during initialization
635//
636static void cleanup_destination_dir(const ConfigReader &config)
637{
638  std::string dest_dir = config.getStringValue("destination_directory");
639  DIR* dir = opendir(dest_dir.c_str());
640  if (dir != NULL) {
641    struct dirent* e;
642    while ((e = readdir(dir)) != 0) {
643      if (e->d_name[0] != '.') {
644        std::string file_path = dest_dir + "/" + e->d_name;
645        remove(file_path.c_str());
646      }
647    }
648    closedir(dir);
649  } else {
650    W_ALOGW("unable to open destination dir %s for cleanup",
651            dest_dir.c_str());
652  }
653}
654
655//
656// Post-processes after profile is collected and converted to protobuf.
657// * GMS core stores processed file sequence numbers in
658//   /data/data/com.google.android.gms/files/perfprofd_processed.txt
659// * Update /data/misc/perfprofd/perfprofd_produced.txt to remove the sequence
660//   numbers that have been processed and append the current seq number
661// Returns true if the current_seq should increment.
662//
663static bool post_process(const ConfigReader &config, int current_seq)
664{
665  std::string dest_dir = config.getStringValue("destination_directory");
666  std::string processed_file_path =
667      config.getStringValue("config_directory") + "/" + PROCESSED_FILENAME;
668  std::string produced_file_path = dest_dir + "/" + PRODUCED_FILENAME;
669
670
671  std::set<int> processed;
672  FILE *fp = fopen(processed_file_path.c_str(), "r");
673  if (fp != NULL) {
674    int seq;
675    while(fscanf(fp, "%d\n", &seq) > 0) {
676      if (remove(android::base::StringPrintf(
677          "%s/perf.data.encoded.%d", dest_dir.c_str(),seq).c_str()) == 0) {
678        processed.insert(seq);
679      }
680    }
681    fclose(fp);
682  }
683
684  std::set<int> produced;
685  fp = fopen(produced_file_path.c_str(), "r");
686  if (fp != NULL) {
687    int seq;
688    while(fscanf(fp, "%d\n", &seq) > 0) {
689      if (processed.find(seq) == processed.end()) {
690        produced.insert(seq);
691      }
692    }
693    fclose(fp);
694  }
695
696  unsigned maxLive = config.getUnsignedValue("max_unprocessed_profiles");
697  if (produced.size() >= maxLive) {
698    return false;
699  }
700
701  produced.insert(current_seq);
702  fp = fopen(produced_file_path.c_str(), "w");
703  if (fp == NULL) {
704    W_ALOGW("Cannot write %s", produced_file_path.c_str());
705    return false;
706  }
707  for (std::set<int>::const_iterator iter = produced.begin();
708       iter != produced.end(); ++iter) {
709    fprintf(fp, "%d\n", *iter);
710  }
711  fclose(fp);
712  chmod(produced_file_path.c_str(),
713        S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
714  return true;
715}
716
717//
718// Collect a perf profile. Steps for this operation are:
719// - kick off 'perf record'
720// - read perf.data, convert to protocol buf
721//
722static PROFILE_RESULT collect_profile(const ConfigReader &config, int seq)
723{
724  //
725  // Collect cpu utilization if enabled
726  //
727  unsigned cpu_utilization = 0;
728  if (config.getUnsignedValue("collect_cpu_utilization")) {
729    cpu_utilization = collect_cpu_utilization();
730  }
731
732  //
733  // Form perf.data file name, perf error output file name
734  //
735  std::string destdir = config.getStringValue("destination_directory");
736  std::string data_file_path(destdir);
737  data_file_path += "/";
738  data_file_path += PERF_OUTPUT;
739  std::string perf_stderr_path(destdir);
740  perf_stderr_path += "/perferr.txt";
741
742  //
743  // Remove any existing perf.data file -- if we don't do this, perf
744  // will rename the old file and we'll have extra cruft lying around.
745  //
746  struct stat statb;
747  if (stat(data_file_path.c_str(), &statb) == 0) { // if file exists...
748    if (unlink(data_file_path.c_str())) {          // then try to remove
749      W_ALOGW("unable to unlink previous perf.data file");
750    }
751  }
752
753  //
754  // The "mpdecision" daemon can cause problems for profile
755  // collection: if it decides to online a CPU partway through the
756  // 'perf record' run, the activity on that CPU will be invisible to
757  // perf, and if it offlines a CPU during the recording this can
758  // sometimes leave the PMU in an unusable state (dmesg errors of the
759  // form "perfevents: unable to request IRQXXX for ...").  To avoid
760  // these issues, if "mpdecision" is running the helper below will
761  // stop the service and then online all available CPUs. The object
762  // destructor (invoked when this routine terminates) will then
763  // restart the service again when needed.
764  //
765  unsigned duration = config.getUnsignedValue("sample_duration");
766  unsigned hardwire = config.getUnsignedValue("hardwire_cpus");
767  unsigned max_duration = config.getUnsignedValue("hardwire_cpus_max_duration");
768  bool take_action = (hardwire && duration <= max_duration);
769  HardwireCpuHelper helper(take_action);
770
771  //
772  // Invoke perf
773  //
774  const char *stack_profile_opt =
775      (config.getUnsignedValue("stack_profile") != 0 ? "-g" : nullptr);
776  std::string perf_path = config.getStringValue("perf_path");
777  unsigned period = config.getUnsignedValue("sampling_period");
778
779  PROFILE_RESULT ret = invoke_perf(perf_path.c_str(),
780                                  period,
781                                  stack_profile_opt,
782                                  duration,
783                                  data_file_path,
784                                  perf_stderr_path);
785  if (ret != OK_PROFILE_COLLECTION) {
786    return ret;
787  }
788
789  //
790  // Read the resulting perf.data file, encode into protocol buffer, then write
791  // the result to the file perf.data.encoded
792  //
793  std::string path = android::base::StringPrintf(
794      "%s.encoded.%d", data_file_path.c_str(), seq);
795  return encode_to_proto(data_file_path, path.c_str(), config, cpu_utilization);
796}
797
798//
799// Assuming that we want to collect a profile every N seconds,
800// randomly partition N into two sub-intervals.
801//
802static void determine_before_after(unsigned &sleep_before_collect,
803                                   unsigned &sleep_after_collect,
804                                   unsigned collection_interval)
805{
806  double frac = erand48(random_seed);
807  sleep_before_collect = (unsigned) (((double)collection_interval) * frac);
808  assert(sleep_before_collect <= collection_interval);
809  sleep_after_collect = collection_interval - sleep_before_collect;
810}
811
812//
813// Set random number generator seed
814//
815static void set_seed(ConfigReader &config)
816{
817  unsigned seed = 0;
818  unsigned use_fixed_seed = config.getUnsignedValue("use_fixed_seed");
819  if (use_fixed_seed) {
820    //
821    // Use fixed user-specified seed
822    //
823    seed = use_fixed_seed;
824  } else {
825    //
826    // Randomized seed
827    //
828    seed = arc4random();
829  }
830  W_ALOGI("random seed set to %u", seed);
831  // Distribute the 32-bit seed into the three 16-bit array
832  // elements. The specific values being written do not especially
833  // matter as long as we are setting them to something based on the seed.
834  random_seed[0] = seed & 0xffff;
835  random_seed[1] = (seed >> 16);
836  random_seed[2] = (random_seed[0] ^ random_seed[1]);
837}
838
839//
840// Initialization
841//
842static void init(ConfigReader &config)
843{
844  if (!config.readFile()) {
845    W_ALOGE("unable to open configuration file %s",
846            config.getConfigFilePath());
847  }
848
849  // Children of init inherit an artificially low OOM score -- this is not
850  // desirable for perfprofd (its OOM score should be on par with
851  // other user processes).
852  std::stringstream oomscore_path;
853  oomscore_path << "/proc/" << getpid() << "/oom_score_adj";
854  if (!android::base::WriteStringToFile("0", oomscore_path.str())) {
855    W_ALOGE("unable to write to %s", oomscore_path.str().c_str());
856  }
857
858  set_seed(config);
859  cleanup_destination_dir(config);
860
861  char propBuf[PROPERTY_VALUE_MAX];
862  propBuf[0] = '\0';
863  property_get("ro.kernel.qemu", propBuf, "");
864  running_in_emulator = (propBuf[0] == '1');
865  property_get("ro.debuggable", propBuf, "");
866  is_debug_build = (propBuf[0] == '1');
867
868  signal(SIGHUP, sig_hup);
869}
870
871//
872// Main routine:
873// 1. parse cmd line args
874// 2. read config file
875// 3. loop: {
876//       sleep for a while
877//       perform a profile collection
878//    }
879//
880int perfprofd_main(int argc, char** argv)
881{
882  ConfigReader config;
883
884  W_ALOGI("starting Android Wide Profiling daemon");
885
886  parse_args(argc, argv);
887  init(config);
888
889  if (!perf_file_to_convert.empty()) {
890    std::string encoded_path = perf_file_to_convert + ".encoded";
891    encode_to_proto(perf_file_to_convert, encoded_path.c_str(), config, 0);
892    return 0;
893  }
894
895  // Early exit if we're not supposed to run on this build flavor
896  if (is_debug_build != 1 &&
897      config.getUnsignedValue("only_debug_build") == 1) {
898    W_ALOGI("early exit due to inappropriate build type");
899    return 0;
900  }
901
902  unsigned iterations = 0;
903  int seq = 0;
904  while(config.getUnsignedValue("main_loop_iterations") == 0 ||
905        iterations < config.getUnsignedValue("main_loop_iterations")) {
906
907    // Figure out where in the collection interval we're going to actually
908    // run perf
909    unsigned sleep_before_collect = 0;
910    unsigned sleep_after_collect = 0;
911    determine_before_after(sleep_before_collect, sleep_after_collect,
912                           config.getUnsignedValue("collection_interval"));
913    perfprofd_sleep(sleep_before_collect);
914
915    // Reread config file -- the uploader may have rewritten it as a result
916    // of a gservices change
917    config.readFile();
918
919    // Check for profiling enabled...
920    CKPROFILE_RESULT ckresult = check_profiling_enabled(config);
921    if (ckresult != DO_COLLECT_PROFILE) {
922      W_ALOGI("profile collection skipped (%s)",
923              ckprofile_result_to_string(ckresult));
924    } else {
925      // Kick off the profiling run...
926      W_ALOGI("initiating profile collection");
927      PROFILE_RESULT result = collect_profile(config, seq);
928      if (result != OK_PROFILE_COLLECTION) {
929        W_ALOGI("profile collection failed (%s)",
930                profile_result_to_string(result));
931      } else {
932        if (post_process(config, seq)) {
933          seq++;
934        }
935        W_ALOGI("profile collection complete");
936      }
937    }
938    perfprofd_sleep(sleep_after_collect);
939    iterations += 1;
940  }
941
942  W_ALOGI("finishing Android Wide Profiling daemon");
943  return 0;
944}
945