Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44e34383 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add wchan data to ANR dump"

parents cccb573f 1489e27b
Loading
Loading
Loading
Loading
+86 −1
Original line number Diff line number Diff line
@@ -22,9 +22,11 @@
#include <sys/poll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#include <chrono>
#include <iomanip>

#include <android-base/cmsg.h>
#include <android-base/file.h>
@@ -42,8 +44,10 @@

using namespace std::chrono_literals;

using android::base::ReadFileToString;
using android::base::SendFileDescriptors;
using android::base::unique_fd;
using android::base::WriteStringToFd;

static bool send_signal(pid_t pid, const DebuggerdDumpType dump_type) {
  const int signal = (dump_type == kDebuggerdJavaBacktrace) ? SIGQUIT : DEBUGGER_SIGNAL;
@@ -65,6 +69,76 @@ static void populate_timeval(struct timeval* tv, const Duration& duration) {
  tv->tv_usec = static_cast<long>(microseconds.count());
}

static void get_wchan_header(pid_t pid, std::stringstream& buffer) {
  struct tm now;
  time_t t = time(nullptr);
  localtime_r(&t, &now);
  char timestamp[32];
  strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &now);
  std::string time_now(timestamp);

  std::string path = "/proc/" + std::to_string(pid) + "/cmdline";

  char proc_name_buf[1024];
  const char* proc_name = nullptr;
  std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(path.c_str(), "r"), &fclose);

  if (fp) {
    proc_name = fgets(proc_name_buf, sizeof(proc_name_buf), fp.get());
  }

  if (!proc_name) {
    proc_name = "<unknown>";
  }

  buffer << "\n----- Waiting Channels: pid " << pid << " at " << time_now << " -----\n"
         << "Cmd line: " << proc_name << "\n";
}

static void get_wchan_footer(pid_t pid, std::stringstream& buffer) {
  buffer << "----- end " << std::to_string(pid) << " -----\n";
}

/**
 * Returns the wchan data for each thread in the process,
 * or empty string if unable to obtain any data.
 */
static std::string get_wchan_data(pid_t pid) {
  std::stringstream buffer;
  std::vector<pid_t> tids;

  if (!android::procinfo::GetProcessTids(pid, &tids)) {
    LOG(WARNING) << "libdebuggerd_client: Failed to get process tids";
    return buffer.str();
  }

  std::stringstream data;
  for (int tid : tids) {
    std::string path = "/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/wchan";
    std::string wchan_str;
    if (!ReadFileToString(path, &wchan_str, true)) {
      PLOG(WARNING) << "libdebuggerd_client: Failed to read \"" << path << "\"";
      continue;
    }
    data << "sysTid=" << std::left << std::setw(10) << tid << wchan_str << "\n";
  }

  if (std::string str = data.str(); !str.empty()) {
    get_wchan_header(pid, buffer);
    buffer << "\n" << str << "\n";
    get_wchan_footer(pid, buffer);
    buffer << "\n";
  }

  return buffer.str();
}

static void dump_wchan_data(const std::string& data, int fd, pid_t pid) {
  if (!WriteStringToFd(data, fd)) {
    LOG(WARNING) << "libdebuggerd_client: Failed to dump wchan data for pid: " << pid;
  }
}

bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int timeout_ms,
                            unique_fd output_fd) {
  pid_t pid = tid;
@@ -261,6 +335,17 @@ int dump_backtrace_to_file_timeout(pid_t tid, DebuggerdDumpType dump_type, int t
  if (copy == -1) {
    return -1;
  }

  // debuggerd_trigger_dump results in every thread in the process being interrupted
  // by a signal, so we need to fetch the wchan data before calling that.
  std::string wchan_data = get_wchan_data(tid);

  int timeout_ms = timeout_secs > 0 ? timeout_secs * 1000 : 0;
  return debuggerd_trigger_dump(tid, dump_type, timeout_ms, std::move(copy)) ? 0 : -1;
  int ret = debuggerd_trigger_dump(tid, dump_type, timeout_ms, std::move(copy)) ? 0 : -1;

  // Dump wchan data, since only privileged processes (CAP_SYS_ADMIN) can read
  // kernel stack traces (/proc/*/stack).
  dump_wchan_data(wchan_data, fd, tid);

  return ret;
}