17e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh/*
27e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh**
37e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh** Copyright 2015, The Android Open Source Project
47e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh**
57e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh** Licensed under the Apache License, Version 2.0 (the "License");
67e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh** you may not use this file except in compliance with the License.
77e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh** You may obtain a copy of the License at
87e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh**
97e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh**     http://www.apache.org/licenses/LICENSE-2.0
107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh**
117e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh** Unless required by applicable law or agreed to in writing, software
127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh** distributed under the License is distributed on an "AS IS" BASIS,
137e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh** See the License for the specific language governing permissions and
157e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh** limitations under the License.
167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh*/
177e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <assert.h>
197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <dirent.h>
207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <errno.h>
217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <fcntl.h>
227e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <signal.h>
237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <stdio.h>
247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <stdlib.h>
257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <string.h>
267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <sys/stat.h>
277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <sys/types.h>
2807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh#include <sys/wait.h>
297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <time.h>
307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <unistd.h>
317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <string>
3207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh#include <sstream>
337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <map>
34f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen#include <set>
357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <cctype>
367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
3766dd09e8e2407082ce93bf0784de641298131912Elliott Hughes#include <android-base/file.h>
3866dd09e8e2407082ce93bf0784de641298131912Elliott Hughes#include <android-base/stringprintf.h>
397e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <cutils/properties.h>
407e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
417e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include "perfprofdcore.h"
427e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include "perfprofdutils.h"
437e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include "perf_data_converter.h"
4407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh#include "cpuconfig.h"
458c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh#include "configreader.h"
467e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
477e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
487e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Perf profiling daemon -- collects system-wide profiles using
497e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
5007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh//       simpleperf record -a
517e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
527e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// and encodes them so that they can be uploaded by a separate service.
537e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
547e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
557e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//......................................................................
567e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
577e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
5807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh// Output file from 'perf record'.
597e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
607e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#define PERF_OUTPUT "perf.data"
617e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
627e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
637e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// This enum holds the results of the "should we profile" configuration check.
647e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
657e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshtypedef enum {
667e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
677e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // All systems go for profile collection.
687e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  DO_COLLECT_PROFILE,
697e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
7058bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen  // The selected configuration directory doesn't exist.
7158bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen  DONT_PROFILE_MISSING_CONFIG_DIR,
727e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
737e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Destination directory does not contain the semaphore file that
747e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // the perf profile uploading service creates when it determines
757e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // that the user has opted "in" for usage data collection. No
767e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // semaphore -> no user approval -> no profiling.
777e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  DONT_PROFILE_MISSING_SEMAPHORE,
787e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
797e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // No perf executable present
807e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  DONT_PROFILE_MISSING_PERF_EXECUTABLE,
817e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
827e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // We're running in the emulator, perf won't be able to do much
837e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  DONT_PROFILE_RUNNING_IN_EMULATOR
847e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
857e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} CKPROFILE_RESULT;
867e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
877e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
887e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Are we running in the emulator? If so, stub out profile collection
897e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Starts as uninitialized (-1), then set to 1 or 0 at init time.
907e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
917e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshstatic int running_in_emulator = -1;
927e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
937e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
947e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Is this a debug build ('userdebug' or 'eng')?
957e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Starts as uninitialized (-1), then set to 1 or 0 at init time.
967e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
977e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshstatic int is_debug_build = -1;
987e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
997e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
100a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov// Path to the perf file to convert and exit? Empty value is the default, daemon mode.
101a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov//
102a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrovstatic std::string perf_file_to_convert = "";
103a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov
104a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov//
1057e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Random number generator seed (set at startup time).
1067e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
1077e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshstatic unsigned short random_seed[3];
1087e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
1097e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
1108c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// SIGHUP handler. Sending SIGHUP to the daemon can be used to break it
1118c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// out of a sleep() call so as to trigger a new collection (debugging)
1127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
1138c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntoshstatic void sig_hup(int /* signum */)
1147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
1158c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  W_ALOGW("SIGHUP received");
1167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
1177e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
1187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
119a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov// Parse command line args. Currently supported flags:
120a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov// *  "-c PATH" sets the path of the config file to PATH.
121a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov// *  "-x PATH" reads PATH as a perf data file and saves it as a file in
122a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov//    perf_profile.proto format. ".encoded" suffix is appended to PATH to form
123a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov//    the output file path.
1247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
1257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshstatic void parse_args(int argc, char** argv)
1267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
1277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  int ac;
1287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
1297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  for (ac = 1; ac < argc; ++ac) {
1307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    if (!strcmp(argv[ac], "-c")) {
1317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      if (ac >= argc-1) {
1327e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh        W_ALOGE("malformed command line: -c option requires argument)");
1337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh        continue;
1347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      }
1358c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      ConfigReader::setConfigFilePath(argv[ac+1]);
1367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      ++ac;
137a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov    } else if (!strcmp(argv[ac], "-x")) {
138a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov      if (ac >= argc-1) {
139a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov        W_ALOGE("malformed command line: -x option requires argument)");
140a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov        continue;
141a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov      }
142a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov      perf_file_to_convert = argv[ac+1];
143a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov      ++ac;
1447e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    } else {
1457e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      W_ALOGE("malformed command line: unknown option or arg %s)", argv[ac]);
1467e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      continue;
1477e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    }
1487e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
1497e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
1507e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
1517e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
1527e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Convert a CKPROFILE_RESULT to a string
1537e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
1547e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshconst char *ckprofile_result_to_string(CKPROFILE_RESULT result)
1557e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
15607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  switch (result) {
1577e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    case DO_COLLECT_PROFILE:
1587e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      return "DO_COLLECT_PROFILE";
15958bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen    case DONT_PROFILE_MISSING_CONFIG_DIR:
16058bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen      return "missing config directory";
1617e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    case DONT_PROFILE_MISSING_SEMAPHORE:
1627e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      return "missing semaphore file";
1637e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    case DONT_PROFILE_MISSING_PERF_EXECUTABLE:
1647e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      return "missing 'perf' executable";
1657e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    case DONT_PROFILE_RUNNING_IN_EMULATOR:
1667e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      return "running in emulator";
1677e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    default: return "unknown";
1687e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
1697e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  return "notreached";
1707e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
1717e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
1727e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
1737e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Convert a PROFILE_RESULT to a string
1747e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
1757e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshconst char *profile_result_to_string(PROFILE_RESULT result)
1767e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
1777e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  switch(result) {
1787e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    case OK_PROFILE_COLLECTION:
1797e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      return "profile collection succeeded";
1807e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    case ERR_FORK_FAILED:
1817e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      return "fork() system call failed";
1827e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    case ERR_PERF_RECORD_FAILED:
1837e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      return "perf record returned bad exit status";
1847e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    case ERR_PERF_ENCODE_FAILED:
1857e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      return "failure encoding perf.data to protobuf";
1867e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    case ERR_OPEN_ENCODED_FILE_FAILED:
1877e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      return "failed to open encoded perf file";
1887e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    case ERR_WRITE_ENCODED_FILE_FAILED:
1897e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      return "write to encoded perf file failed";
1907e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    default: return "unknown";
1917e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
1927e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  return "notreached";
1937e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
1947e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
1957e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
1967e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Check to see whether we should perform a profile collection
1977e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
1987e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshstatic CKPROFILE_RESULT check_profiling_enabled(ConfigReader &config)
1997e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
2007e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
2017e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Profile collection in the emulator doesn't make sense
2027e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
2037e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  assert(running_in_emulator != -1);
2047e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  if (running_in_emulator) {
2057e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    return DONT_PROFILE_RUNNING_IN_EMULATOR;
2067e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
2077e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
2087e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
20958bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen  // Check for existence of semaphore file in config directory
2107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
21158bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen  if (access(config.getStringValue("config_directory").c_str(), F_OK) == -1) {
21258bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen    W_ALOGW("unable to open config directory %s: (%s)",
21358bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen            config.getStringValue("config_directory").c_str(), strerror(errno));
21458bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen    return DONT_PROFILE_MISSING_CONFIG_DIR;
2157e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
2167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
21758bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen
21858bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen  // Check for existence of semaphore file
21958bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen  std::string semaphore_filepath = config.getStringValue("config_directory")
22058bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen                                   + "/" + SEMAPHORE_FILENAME;
22158bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen  if (access(semaphore_filepath.c_str(), F_OK) == -1) {
22258bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen    return DONT_PROFILE_MISSING_SEMAPHORE;
22358bade36c738ed96137cfcc8d15f0505f085b5aeDehao Chen  }
2247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
22507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // Check for existence of simpleperf/perf executable
2267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  std::string pp = config.getStringValue("perf_path");
2277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  if (access(pp.c_str(), R_OK|X_OK) == -1) {
2287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    W_ALOGW("unable to access/execute %s", pp.c_str());
2297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    return DONT_PROFILE_MISSING_PERF_EXECUTABLE;
2307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
2317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
2327e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
2337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // We are good to go
2347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
2357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  return DO_COLLECT_PROFILE;
2367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
2377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
2388c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntoshbool get_booting()
239ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh{
2408c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  char propBuf[PROPERTY_VALUE_MAX];
2418c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  propBuf[0] = '\0';
2428c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  property_get("sys.boot_completed", propBuf, "");
2438c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  return (propBuf[0] != '1');
2448c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh}
2458c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
2468c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh//
2478c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// Constructor takes a timeout (in seconds) and a child pid; If an
2488c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// alarm set for the specified number of seconds triggers, then a
2498c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// SIGKILL is sent to the child. Destructor resets alarm. Example:
2508c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh//
2518c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh//       pid_t child_pid = ...;
2528c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh//       { AlarmHelper h(10, child_pid);
2538c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh//         ... = read_from_child(child_pid, ...);
2548c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh//       }
2558c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh//
2568c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// NB: this helper is not re-entrant-- avoid nested use or
2578c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// use by multiple threads
2588c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh//
2598c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntoshclass AlarmHelper {
2608c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh public:
2618c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  AlarmHelper(unsigned num_seconds, pid_t child)
2628c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  {
2638c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    struct sigaction sigact;
2648c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    assert(child);
2658c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    assert(child_ == 0);
2668c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    memset(&sigact, 0, sizeof(sigact));
2678c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    sigact.sa_sigaction = handler;
2688c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    sigaction(SIGALRM, &sigact, &oldsigact_);
2698c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    child_ = child;
2708c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    alarm(num_seconds);
2718c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
2728c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  ~AlarmHelper()
2738c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  {
2748c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    alarm(0);
2758c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    child_ = 0;
2768c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    sigaction(SIGALRM, &oldsigact_, NULL);
2778c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
2788c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  static void handler(int, siginfo_t *, void *);
2798c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
2808c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh private:
2818c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  struct sigaction oldsigact_;
2828c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  static pid_t child_;
2838c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh};
2848c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
2858c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntoshpid_t AlarmHelper::child_;
2868c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
2878c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntoshvoid AlarmHelper::handler(int, siginfo_t *, void *)
2888c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh{
2898c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  W_ALOGW("SIGALRM timeout");
2908c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  kill(child_, SIGKILL);
2918c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh}
2928c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
2938c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh//
2948c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// This implementation invokes "dumpsys media.camera" and inspects the
2958c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// output to determine if any camera clients are active. NB: this is
2968c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// currently disable (via config option) until the selinux issues can
2978c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// be sorted out. Another possible implementation (not yet attempted)
2988c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// would be to use the binder to call into the native camera service
2998c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh// via "ICameraService".
3008c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh//
3018c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntoshbool get_camera_active()
3028c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh{
3038c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  int pipefds[2];
3048c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (pipe2(pipefds, O_CLOEXEC) != 0) {
3058c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    W_ALOGE("pipe2() failed (%s)", strerror(errno));
3068c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    return false;
3078c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
3088c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  pid_t pid = fork();
3098c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (pid == -1) {
3108c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    W_ALOGE("fork() failed (%s)", strerror(errno));
3118c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    close(pipefds[0]);
3128c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    close(pipefds[1]);
3138c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    return false;
3148c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  } else if (pid == 0) {
3158c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    // child
3168c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    close(pipefds[0]);
3178c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    dup2(pipefds[1], fileno(stderr));
3188c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    dup2(pipefds[1], fileno(stdout));
3198c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    const char *argv[10];
3208c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    unsigned slot = 0;
3218c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    argv[slot++] = "/system/bin/dumpsys";
3228c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    argv[slot++] = "media.camera";
3238c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    argv[slot++] = nullptr;
3248c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    execvp(argv[0], (char * const *)argv);
3258c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    W_ALOGE("execvp() failed (%s)", strerror(errno));
3268c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    return false;
3278c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
3288c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  // parent
3298c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  AlarmHelper helper(10, pid);
3308c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  close(pipefds[1]);
3318c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
3328c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  // read output
3338c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  bool have_cam = false;
3348c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  bool have_clients = true;
3358c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  std::string dump_output;
3368c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  bool result = android::base::ReadFdToString(pipefds[0], &dump_output);
3378c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  close(pipefds[0]);
3388c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (result) {
3398c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    std::stringstream ss(dump_output);
3408c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    std::string line;
3418c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    while (std::getline(ss,line,'\n')) {
3428c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      if (line.find("Camera module API version:") !=
3438c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh          std::string::npos) {
3448c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh        have_cam = true;
3458c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      }
3468c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      if (line.find("No camera module available") !=
3478c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh          std::string::npos ||
3488c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh          line.find("No active camera clients yet") !=
3498c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh          std::string::npos) {
3508c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh        have_clients = false;
3518c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      }
3528c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    }
3538c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
3548c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
3558c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  // reap child (no zombies please)
3568c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  int st = 0;
3578c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  TEMP_FAILURE_RETRY(waitpid(pid, &st, 0));
3588c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  return have_cam && have_clients;
3598c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh}
3608c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
3618c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntoshbool get_charging()
3628c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh{
3638c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  std::string psdir("/sys/class/power_supply");
3648c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  DIR* dir = opendir(psdir.c_str());
3658c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (dir == NULL) {
3668c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    W_ALOGE("Failed to open dir %s (%s)", psdir.c_str(), strerror(errno));
3678c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    return false;
3688c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
3698c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  struct dirent* e;
3708c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  bool result = false;
3718c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  while ((e = readdir(dir)) != 0) {
3728c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    if (e->d_name[0] != '.') {
3738c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      std::string online_path = psdir + "/" + e->d_name + "/online";
3748c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      std::string contents;
3758c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      int value = 0;
3768c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      if (android::base::ReadFileToString(online_path.c_str(), &contents) &&
3778c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh          sscanf(contents.c_str(), "%d", &value) == 1) {
3788c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh        if (value) {
3798c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh          result = true;
3808c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh          break;
3818c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh        }
3828c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      }
3838c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    }
3848c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
3858c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  closedir(dir);
3868c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  return result;
3878c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh}
3888c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
3898c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntoshbool postprocess_proc_stat_contents(const std::string &pscontents,
3908c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh                                    long unsigned *idleticks,
3918c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh                                    long unsigned *remainingticks)
3928c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh{
3938c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  long unsigned usertime, nicetime, systime, idletime, iowaittime;
3948c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  long unsigned irqtime, softirqtime;
3958c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
3968c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  int rc = sscanf(pscontents.c_str(), "cpu  %lu %lu %lu %lu %lu %lu %lu",
3978c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh                  &usertime, &nicetime, &systime, &idletime,
3988c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh                  &iowaittime, &irqtime, &softirqtime);
3998c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (rc != 7) {
4008c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    return false;
4018c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
4028c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  *idleticks = idletime;
4038c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  *remainingticks = usertime + nicetime + systime + iowaittime + irqtime + softirqtime;
4048c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  return true;
4058c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh}
4068c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
4078c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntoshunsigned collect_cpu_utilization()
4088c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh{
4098c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  std::string contents;
4108c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  long unsigned idle[2];
4118c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  long unsigned busy[2];
4128c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  for (unsigned iter = 0; iter < 2; ++iter) {
4138c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    if (!android::base::ReadFileToString("/proc/stat", &contents)) {
4148c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      return 0;
4158c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    }
4168c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    if (!postprocess_proc_stat_contents(contents, &idle[iter], &busy[iter])) {
4178c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      return 0;
4188c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    }
4198c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    if (iter == 0) {
4208c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh      sleep(1);
4218c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    }
4228c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
4238c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  long unsigned total_delta = (idle[1] + busy[1]) - (idle[0] + busy[0]);
4248c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  long unsigned busy_delta = busy[1] - busy[0];
4258c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  return busy_delta * 100 / total_delta;
4268c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh}
4278c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
4288c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntoshstatic void annotate_encoded_perf_profile(wireless_android_play_playlog::AndroidPerfProfile *profile,
4298c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh                                          const ConfigReader &config,
4308c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh                                          unsigned cpu_utilization)
4318c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh{
4328c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  //
4338c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  // Incorporate cpu utilization (collected prior to perf run)
4348c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  //
4358c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (config.getUnsignedValue("collect_cpu_utilization")) {
4368c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    profile->set_cpu_utilization(cpu_utilization);
4378c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
4388c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
439ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  //
440ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  // Load average as reported by the kernel
441ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  //
442ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  std::string load;
443ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  double fload = 0.0;
444ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  if (android::base::ReadFileToString("/proc/loadavg", &load) &&
445ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh      sscanf(load.c_str(), "%lf", &fload) == 1) {
446ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh    int iload = static_cast<int>(fload * 100.0);
447ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh    profile->set_sys_load_average(iload);
448ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  } else {
449ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh    W_ALOGE("Failed to read or scan /proc/loadavg (%s)", strerror(errno));
450ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  }
451ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh
452ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  //
4538c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  // Device still booting? Camera in use? Plugged into charger?
4548c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  //
4558c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  bool is_booting = get_booting();
4568c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (config.getUnsignedValue("collect_booting")) {
4578c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    profile->set_booting(is_booting);
4588c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
4598c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (config.getUnsignedValue("collect_camera_active")) {
4608c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    profile->set_camera_active(is_booting ? false : get_camera_active());
4618c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
4628c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (config.getUnsignedValue("collect_charging_state")) {
4638c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    profile->set_on_charger(get_charging());
4648c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
4658c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
4668c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  //
467ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  // Examine the contents of wake_unlock to determine whether the
468ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  // device display is on or off. NB: is this really the only way to
469ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  // determine this info?
470ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  //
471ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  std::string disp;
472ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  if (android::base::ReadFileToString("/sys/power/wake_unlock", &disp)) {
473ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh    bool ison = (strstr(disp.c_str(), "PowerManagerService.Display") == 0);
474ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh    profile->set_display_on(ison);
475ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  } else {
476ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh    W_ALOGE("Failed to read /sys/power/wake_unlock (%s)", strerror(errno));
477ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  }
478ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh}
479ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh
4807e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshinline char* string_as_array(std::string* str) {
4817e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  return str->empty() ? NULL : &*str->begin();
4827e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
4837e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
4847e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshPROFILE_RESULT encode_to_proto(const std::string &data_file_path,
4858c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh                               const char *encoded_file_path,
4868c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh                               const ConfigReader &config,
4878c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh                               unsigned cpu_utilization)
4887e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
4897e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
4907e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Open and read perf.data file
4917e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
4927e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  const wireless_android_play_playlog::AndroidPerfProfile &encodedProfile =
4937e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      wireless_android_logging_awp::RawPerfDataToAndroidPerfProfile(data_file_path);
4947e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
4957e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
4967e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Issue error if no samples
4977e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
4987e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  if (encodedProfile.programs().size() == 0) {
4997e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    return ERR_PERF_ENCODE_FAILED;
5007e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
5017e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
502ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  // All of the info in 'encodedProfile' is derived from the perf.data file;
5038c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  // here we tack display status, cpu utilization, system load, etc.
504ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh  wireless_android_play_playlog::AndroidPerfProfile &prof =
505ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh      const_cast<wireless_android_play_playlog::AndroidPerfProfile&>
506ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh      (encodedProfile);
5078c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  annotate_encoded_perf_profile(&prof, config, cpu_utilization);
508ebb946827ffbbb7df4c41be262a627c02bd95888Than McIntosh
5097e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
5107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Serialize protobuf to array
5117e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
5127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  int size = encodedProfile.ByteSize();
5137e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  std::string data;
5147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  data.resize(size);
5157e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  ::google::protobuf::uint8* dtarget =
5167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh        reinterpret_cast<::google::protobuf::uint8*>(string_as_array(&data));
5177e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  encodedProfile.SerializeWithCachedSizesToArray(dtarget);
5187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
5197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
5207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Open file and write encoded data to it
5217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
522f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  FILE *fp = fopen(encoded_file_path, "w");
5237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  if (!fp) {
5247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    return ERR_OPEN_ENCODED_FILE_FAILED;
5257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
5267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  size_t fsiz = size;
5277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  if (fwrite(dtarget, fsiz, 1, fp) != 1) {
5287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    fclose(fp);
5297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    return ERR_WRITE_ENCODED_FILE_FAILED;
5307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
5317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  fclose(fp);
532f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  chmod(encoded_file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
5337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
5347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  return OK_PROFILE_COLLECTION;
5357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
5367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
5377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
53807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh// Invoke "perf record". Return value is OK_PROFILE_COLLECTION for
53907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh// success, or some other error code if something went wrong.
54007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh//
54107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntoshstatic PROFILE_RESULT invoke_perf(const std::string &perf_path,
54207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh                                  unsigned sampling_period,
54307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh                                  const char *stack_profile_opt,
54407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh                                  unsigned duration,
54507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh                                  const std::string &data_file_path,
54607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh                                  const std::string &perf_stderr_path)
54707f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh{
54807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  pid_t pid = fork();
54907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
55007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  if (pid == -1) {
55107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    return ERR_FORK_FAILED;
55207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  }
55307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
55407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  if (pid == 0) {
55507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // child
55607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
55707f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // Open file to receive stderr/stdout from perf
55807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    FILE *efp = fopen(perf_stderr_path.c_str(), "w");
55907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    if (efp) {
56007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh      dup2(fileno(efp), STDERR_FILENO);
56107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh      dup2(fileno(efp), STDOUT_FILENO);
56207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    } else {
56307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh      W_ALOGW("unable to open %s for writing", perf_stderr_path.c_str());
56407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    }
56507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
56607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // marshall arguments
567e42c1f126a76b4ed4f95ef8fcdfea6866002c185Than McIntosh    constexpr unsigned max_args = 13;
56807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    const char *argv[max_args];
56907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    unsigned slot = 0;
57007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    argv[slot++] = perf_path.c_str();
57107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    argv[slot++] = "record";
57207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
57307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // -o perf.data
57407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    argv[slot++] = "-o";
57507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    argv[slot++] = data_file_path.c_str();
57607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
57707f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // -c N
57807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    argv[slot++] = "-c";
579f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    std::string p_str = android::base::StringPrintf("%u", sampling_period);
580f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    argv[slot++] = p_str.c_str();
58107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
58207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // -g if desired
58307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    if (stack_profile_opt)
58407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh      argv[slot++] = stack_profile_opt;
58507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
58607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // system wide profiling
58707f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    argv[slot++] = "-a";
58807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
589e42c1f126a76b4ed4f95ef8fcdfea6866002c185Than McIntosh    // no need for kernel symbols
590e42c1f126a76b4ed4f95ef8fcdfea6866002c185Than McIntosh    argv[slot++] = "--no-dump-kernel-symbols";
591e42c1f126a76b4ed4f95ef8fcdfea6866002c185Than McIntosh
59207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // sleep <duration>
59307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    argv[slot++] = "/system/bin/sleep";
594f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    std::string d_str = android::base::StringPrintf("%u", duration);
595f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    argv[slot++] = d_str.c_str();
59607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
59707f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // terminator
59807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    argv[slot++] = nullptr;
59907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    assert(slot < max_args);
60007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
60107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // record the final command line in the error output file for
60207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // posterity/debugging purposes
60307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    fprintf(stderr, "perf invocation (pid=%d):\n", getpid());
60407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    for (unsigned i = 0; argv[i] != nullptr; ++i) {
60507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh      fprintf(stderr, "%s%s", i ? " " : "", argv[i]);
60607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    }
60707f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    fprintf(stderr, "\n");
60807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
60907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // exec
61007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    execvp(argv[0], (char * const *)argv);
61107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    fprintf(stderr, "exec failed: %s\n", strerror(errno));
61207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    exit(1);
61307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
61407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  } else {
61507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    // parent
61607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    int st = 0;
61707f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    pid_t reaped = TEMP_FAILURE_RETRY(waitpid(pid, &st, 0));
61807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
61907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    if (reaped == -1) {
62007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh      W_ALOGW("waitpid failed: %s", strerror(errno));
62107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    } else if (WIFSIGNALED(st)) {
62207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh      W_ALOGW("perf killed by signal %d", WTERMSIG(st));
62307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    } else if (WEXITSTATUS(st) != 0) {
62407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh      W_ALOGW("perf bad exit status %d", WEXITSTATUS(st));
62507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    } else {
62607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh      return OK_PROFILE_COLLECTION;
62707f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    }
62807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  }
62907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
63007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  return ERR_PERF_RECORD_FAILED;
63107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh}
63207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
63307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh//
634f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen// Remove all files in the destination directory during initialization
635f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen//
636f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chenstatic void cleanup_destination_dir(const ConfigReader &config)
637f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen{
638f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  std::string dest_dir = config.getStringValue("destination_directory");
639f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  DIR* dir = opendir(dest_dir.c_str());
640f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  if (dir != NULL) {
641f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    struct dirent* e;
642f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    while ((e = readdir(dir)) != 0) {
643f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen      if (e->d_name[0] != '.') {
644f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen        std::string file_path = dest_dir + "/" + e->d_name;
645f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen        remove(file_path.c_str());
646f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen      }
647f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    }
648f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    closedir(dir);
649f353d8bf370eab2117e6259630f5540f12b361b0Than McIntosh  } else {
650f353d8bf370eab2117e6259630f5540f12b361b0Than McIntosh    W_ALOGW("unable to open destination dir %s for cleanup",
651f353d8bf370eab2117e6259630f5540f12b361b0Than McIntosh            dest_dir.c_str());
652f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  }
653f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen}
654f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen
655f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen//
656f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen// Post-processes after profile is collected and converted to protobuf.
657f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen// * GMS core stores processed file sequence numbers in
658f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen//   /data/data/com.google.android.gms/files/perfprofd_processed.txt
659f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen// * Update /data/misc/perfprofd/perfprofd_produced.txt to remove the sequence
660f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen//   numbers that have been processed and append the current seq number
661f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen// Returns true if the current_seq should increment.
662f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen//
663f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chenstatic bool post_process(const ConfigReader &config, int current_seq)
664f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen{
665f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  std::string dest_dir = config.getStringValue("destination_directory");
666f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  std::string processed_file_path =
667f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen      config.getStringValue("config_directory") + "/" + PROCESSED_FILENAME;
668f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  std::string produced_file_path = dest_dir + "/" + PRODUCED_FILENAME;
669f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen
670f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen
671f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  std::set<int> processed;
672f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  FILE *fp = fopen(processed_file_path.c_str(), "r");
673f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  if (fp != NULL) {
674f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    int seq;
675f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    while(fscanf(fp, "%d\n", &seq) > 0) {
676f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen      if (remove(android::base::StringPrintf(
677f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen          "%s/perf.data.encoded.%d", dest_dir.c_str(),seq).c_str()) == 0) {
678f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen        processed.insert(seq);
679f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen      }
680f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    }
681f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    fclose(fp);
682f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  }
683f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen
684f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  std::set<int> produced;
685f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  fp = fopen(produced_file_path.c_str(), "r");
686f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  if (fp != NULL) {
687f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    int seq;
688f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    while(fscanf(fp, "%d\n", &seq) > 0) {
689f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen      if (processed.find(seq) == processed.end()) {
690f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen        produced.insert(seq);
691f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen      }
692f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    }
693f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    fclose(fp);
694f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  }
695f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen
696f353d8bf370eab2117e6259630f5540f12b361b0Than McIntosh  unsigned maxLive = config.getUnsignedValue("max_unprocessed_profiles");
697f353d8bf370eab2117e6259630f5540f12b361b0Than McIntosh  if (produced.size() >= maxLive) {
698f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    return false;
699f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  }
700f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen
701f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  produced.insert(current_seq);
702f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  fp = fopen(produced_file_path.c_str(), "w");
703f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  if (fp == NULL) {
704f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    W_ALOGW("Cannot write %s", produced_file_path.c_str());
705f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    return false;
706f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  }
707f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  for (std::set<int>::const_iterator iter = produced.begin();
708f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen       iter != produced.end(); ++iter) {
709f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen    fprintf(fp, "%d\n", *iter);
710f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  }
711f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  fclose(fp);
712f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  chmod(produced_file_path.c_str(),
713f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen        S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
714f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  return true;
715f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen}
716f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen
717f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen//
7187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Collect a perf profile. Steps for this operation are:
7197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// - kick off 'perf record'
7207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// - read perf.data, convert to protocol buf
7217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
722f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chenstatic PROFILE_RESULT collect_profile(const ConfigReader &config, int seq)
7237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
7247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
7258c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  // Collect cpu utilization if enabled
7268c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  //
7278c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  unsigned cpu_utilization = 0;
7288c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (config.getUnsignedValue("collect_cpu_utilization")) {
7298c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    cpu_utilization = collect_cpu_utilization();
7308c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
7318c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
7328c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  //
7337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Form perf.data file name, perf error output file name
7347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
7357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  std::string destdir = config.getStringValue("destination_directory");
7367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  std::string data_file_path(destdir);
7377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  data_file_path += "/";
7387e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  data_file_path += PERF_OUTPUT;
7397e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  std::string perf_stderr_path(destdir);
7407e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  perf_stderr_path += "/perferr.txt";
7417e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
7427e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
7437e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Remove any existing perf.data file -- if we don't do this, perf
7447e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // will rename the old file and we'll have extra cruft lying around.
7457e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
7467e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  struct stat statb;
7477e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  if (stat(data_file_path.c_str(), &statb) == 0) { // if file exists...
7487e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    if (unlink(data_file_path.c_str())) {          // then try to remove
7497e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      W_ALOGW("unable to unlink previous perf.data file");
7507e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    }
7517e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
7527e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
7537e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
75407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // The "mpdecision" daemon can cause problems for profile
75507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // collection: if it decides to online a CPU partway through the
75607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // 'perf record' run, the activity on that CPU will be invisible to
75707f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // perf, and if it offlines a CPU during the recording this can
75807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // sometimes leave the PMU in an unusable state (dmesg errors of the
75907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // form "perfevents: unable to request IRQXXX for ...").  To avoid
76007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // these issues, if "mpdecision" is running the helper below will
76107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // stop the service and then online all available CPUs. The object
76207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // destructor (invoked when this routine terminates) will then
76307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // restart the service again when needed.
7647e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
7657e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  unsigned duration = config.getUnsignedValue("sample_duration");
76607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  unsigned hardwire = config.getUnsignedValue("hardwire_cpus");
76707f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  unsigned max_duration = config.getUnsignedValue("hardwire_cpus_max_duration");
76807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  bool take_action = (hardwire && duration <= max_duration);
76907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  HardwireCpuHelper helper(take_action);
77007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
77107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  //
77207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // Invoke perf
77307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  //
77407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  const char *stack_profile_opt =
77507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh      (config.getUnsignedValue("stack_profile") != 0 ? "-g" : nullptr);
77607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  std::string perf_path = config.getStringValue("perf_path");
7777e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  unsigned period = config.getUnsignedValue("sampling_period");
77807f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh
77907f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  PROFILE_RESULT ret = invoke_perf(perf_path.c_str(),
78007f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh                                  period,
78107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh                                  stack_profile_opt,
78207f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh                                  duration,
78307f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh                                  data_file_path,
78407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh                                  perf_stderr_path);
78507f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  if (ret != OK_PROFILE_COLLECTION) {
78607f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh    return ret;
7877e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
7887e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
7897e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
7907e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Read the resulting perf.data file, encode into protocol buffer, then write
79107f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  // the result to the file perf.data.encoded
7927e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  //
793f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  std::string path = android::base::StringPrintf(
794f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen      "%s.encoded.%d", data_file_path.c_str(), seq);
7958c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  return encode_to_proto(data_file_path, path.c_str(), config, cpu_utilization);
7967e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
7977e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
7987e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
7997e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Assuming that we want to collect a profile every N seconds,
8007e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// randomly partition N into two sub-intervals.
8017e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
8027e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshstatic void determine_before_after(unsigned &sleep_before_collect,
8037e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh                                   unsigned &sleep_after_collect,
8047e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh                                   unsigned collection_interval)
8057e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
8067e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  double frac = erand48(random_seed);
8077e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  sleep_before_collect = (unsigned) (((double)collection_interval) * frac);
8087e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  assert(sleep_before_collect <= collection_interval);
8097e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  sleep_after_collect = collection_interval - sleep_before_collect;
8107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
8117e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
8127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
8137e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Set random number generator seed
8147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
8157e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshstatic void set_seed(ConfigReader &config)
8167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
8177e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  unsigned seed = 0;
8187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  unsigned use_fixed_seed = config.getUnsignedValue("use_fixed_seed");
8197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  if (use_fixed_seed) {
8207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    //
8217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    // Use fixed user-specified seed
8227e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    //
8237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    seed = use_fixed_seed;
8247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  } else {
8257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    //
8267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    // Randomized seed
8277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    //
8287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    seed = arc4random();
8297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
8307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  W_ALOGI("random seed set to %u", seed);
8317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Distribute the 32-bit seed into the three 16-bit array
8327e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // elements. The specific values being written do not especially
8337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // matter as long as we are setting them to something based on the seed.
8347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  random_seed[0] = seed & 0xffff;
8357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  random_seed[1] = (seed >> 16);
8367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  random_seed[2] = (random_seed[0] ^ random_seed[1]);
8377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
8387e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
8397e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
8407e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Initialization
8417e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
8427e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshstatic void init(ConfigReader &config)
8437e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
8448c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  if (!config.readFile()) {
8458c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    W_ALOGE("unable to open configuration file %s",
8468c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh            config.getConfigFilePath());
8478c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh  }
8488c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh
849fd6bb2d486084a0eeeb11767b17234cf4a23159dThan McIntosh  // Children of init inherit an artificially low OOM score -- this is not
850fd6bb2d486084a0eeeb11767b17234cf4a23159dThan McIntosh  // desirable for perfprofd (its OOM score should be on par with
851fd6bb2d486084a0eeeb11767b17234cf4a23159dThan McIntosh  // other user processes).
852fd6bb2d486084a0eeeb11767b17234cf4a23159dThan McIntosh  std::stringstream oomscore_path;
853fd6bb2d486084a0eeeb11767b17234cf4a23159dThan McIntosh  oomscore_path << "/proc/" << getpid() << "/oom_score_adj";
854fd6bb2d486084a0eeeb11767b17234cf4a23159dThan McIntosh  if (!android::base::WriteStringToFile("0", oomscore_path.str())) {
855fd6bb2d486084a0eeeb11767b17234cf4a23159dThan McIntosh    W_ALOGE("unable to write to %s", oomscore_path.str().c_str());
856fd6bb2d486084a0eeeb11767b17234cf4a23159dThan McIntosh  }
857fd6bb2d486084a0eeeb11767b17234cf4a23159dThan McIntosh
8587e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  set_seed(config);
859f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  cleanup_destination_dir(config);
8607e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
8617e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  char propBuf[PROPERTY_VALUE_MAX];
8627e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  propBuf[0] = '\0';
8637e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  property_get("ro.kernel.qemu", propBuf, "");
8647e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  running_in_emulator = (propBuf[0] == '1');
8657e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  property_get("ro.debuggable", propBuf, "");
8667e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  is_debug_build = (propBuf[0] == '1');
8677e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
8687e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  signal(SIGHUP, sig_hup);
8697e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
8707e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
8717e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
8727e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Main routine:
8737e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// 1. parse cmd line args
8747e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// 2. read config file
8757e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// 3. loop: {
8767e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//       sleep for a while
8777e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//       perform a profile collection
8787e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//    }
8797e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh//
8807e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshint perfprofd_main(int argc, char** argv)
8817e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{
8827e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  ConfigReader config;
8837e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
8847e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  W_ALOGI("starting Android Wide Profiling daemon");
8857e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
8867e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  parse_args(argc, argv);
8877e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  init(config);
8887e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
889a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov  if (!perf_file_to_convert.empty()) {
890a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov    std::string encoded_path = perf_file_to_convert + ".encoded";
891a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov    encode_to_proto(perf_file_to_convert, encoded_path.c_str(), config, 0);
892a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov    return 0;
893a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov  }
894a5cbb7a0538bd63d87f11be13ce1d85bb594e20dAlexey Alexandrov
8957e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  // Early exit if we're not supposed to run on this build flavor
8967e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  if (is_debug_build != 1 &&
8977e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      config.getUnsignedValue("only_debug_build") == 1) {
8987e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    W_ALOGI("early exit due to inappropriate build type");
8997e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    return 0;
9007e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
9017e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
9027e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  unsigned iterations = 0;
903f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen  int seq = 0;
90407f00fd438a0c10bc6b2487352d09eb0a648db40Than McIntosh  while(config.getUnsignedValue("main_loop_iterations") == 0 ||
9057e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh        iterations < config.getUnsignedValue("main_loop_iterations")) {
9067e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
9077e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    // Figure out where in the collection interval we're going to actually
9087e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    // run perf
9097e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    unsigned sleep_before_collect = 0;
9107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    unsigned sleep_after_collect = 0;
9117e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    determine_before_after(sleep_before_collect, sleep_after_collect,
9127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh                           config.getUnsignedValue("collection_interval"));
9137e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    perfprofd_sleep(sleep_before_collect);
9147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
915f353d8bf370eab2117e6259630f5540f12b361b0Than McIntosh    // Reread config file -- the uploader may have rewritten it as a result
916f353d8bf370eab2117e6259630f5540f12b361b0Than McIntosh    // of a gservices change
9178c7c7db1f1a23ab0c575cc217bed6b45f42b9ba5Than McIntosh    config.readFile();
9187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
9197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    // Check for profiling enabled...
9207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    CKPROFILE_RESULT ckresult = check_profiling_enabled(config);
9217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    if (ckresult != DO_COLLECT_PROFILE) {
9227e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      W_ALOGI("profile collection skipped (%s)",
9237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh              ckprofile_result_to_string(ckresult));
9247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    } else {
9257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      // Kick off the profiling run...
9267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      W_ALOGI("initiating profile collection");
927f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen      PROFILE_RESULT result = collect_profile(config, seq);
9287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      if (result != OK_PROFILE_COLLECTION) {
9297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh        W_ALOGI("profile collection failed (%s)",
9307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh                profile_result_to_string(result));
9317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      } else {
932f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen        if (post_process(config, seq)) {
933f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen          seq++;
934f4605017b29dd98232af9385e71079a3ba0297f1Dehao Chen        }
9357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh        W_ALOGI("profile collection complete");
9367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh      }
9377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    }
9387e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    perfprofd_sleep(sleep_after_collect);
9397e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh    iterations += 1;
9407e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  }
9417e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh
9427e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  W_ALOGI("finishing Android Wide Profiling daemon");
9437e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh  return 0;
9447e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}
945