// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "crash-reporter/arc_collector.h"

#include <sysexits.h>
#include <unistd.h>

#include <ctime>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include <base/files/file.h>
#include <base/files/file_enumerator.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/stringize_macros.h>
#include <base/time/time.h>
#include <brillo/key_value_store.h>
#include <brillo/process.h>

using base::File;
using base::FilePath;
using base::ReadFileToString;
using base::TimeDelta;
using base::TimeTicks;

using brillo::ProcessImpl;

namespace {

const FilePath kContainersDir("/run/containers");
const FilePath::StringType kArcDirPattern("android_*");
const FilePath kContainerPid("container.pid");

const FilePath kArcBuildProp("system/build.prop");  // Relative to ARC root.

const char kCoreCollectorPath[] = "/usr/bin/core_collector";
#if __WORDSIZE == 64
const char kCoreCollector32Path[] = "/usr/bin/core_collector32";
#endif

const char kChromePath[] = "/opt/google/chrome/chrome";

const char kArcProduct[] = "ChromeOS_ARC";

// Metadata fields included in reports.
const char kArcVersionField[] = "arc_version";
const char kBoardField[] = "board";
const char kChromeOsVersionField[] = "chrome_os_version";
const char kCpuAbiField[] = "cpu_abi";
const char kCrashTypeField[] = "crash_type";
const char kDeviceField[] = "device";
const char kExceptionInfoField[] = "exception_info";
const char kProcessField[] = "process";
const char kProductField[] = "prod";
const char kSignatureField[] = "sig";
const char kUptimeField[] = "uptime";

// If this metadata key is set to "true", the report is uploaded silently, i.e.
// it does not appear in chrome://crashes.
const char kSilentKey[] = "silent";

// Keys for crash log headers.
const char kBuildKey[] = "Build";
const char kProcessKey[] = "Process";
const char kSubjectKey[] = "Subject";

const std::pair<const char *, const char *> kHeaderToFieldMapping[] = {
  { "Crash-Tag", "crash_tag" },
  { "NDK-Execution", "ndk_execution" },
  { "Package", "package" },
  { "Target-SDK", "target_sdk" }
};

// Keys for build properties.
const char kBoardProperty[] = "ro.product.board";
const char kCpuAbiProperty[] = "ro.product.cpu.abi";
const char kDeviceProperty[] = "ro.product.device";
const char kFingerprintProperty[] = "ro.build.fingerprint";

const size_t kBufferSize = 4096;

inline bool IsAppProcess(const std::string &name) {
  return name == "app_process32" || name == "app_process64";
}

inline bool IsSilentReport(const std::string &type) {
  return type == "system_app_wtf" || type == "system_server_wtf";
}

inline TimeTicks ToSeconds(const TimeTicks &time) {
  return TimeTicks::FromInternalValue(
      TimeDelta::FromSeconds(TimeDelta::FromInternalValue(
          time.ToInternalValue()).InSeconds()).ToInternalValue());
}

bool ReadCrashLogFromStdin(std::stringstream *stream);

bool HasExceptionInfo(const std::string &type);
const char *GetSubjectTag(const std::string &type);

bool GetChromeVersion(std::string *version);

bool GetArcRoot(FilePath *root);
bool GetArcProperties(std::string *version,
                      std::string *device,
                      std::string *board,
                      std::string *cpu_abi);

// Runs |process| and redirects |fd| to |output|. Returns the exit code, or -1
// if the process failed to start.
int RunAndCaptureOutput(ProcessImpl *process, int fd, std::string *output);

std::string FormatDuration(uint64_t seconds);

}  // namespace

ArcCollector::ArcCollector()
    : ArcCollector(ContextPtr(new ArcContext(this))) {
}

ArcCollector::ArcCollector(ContextPtr context)
    : UserCollectorBase("ARC", true),
      context_(std::move(context)) {
}

bool ArcCollector::IsArcProcess(pid_t pid) const {
  pid_t arc_pid;
  if (!context_->GetArcPid(&arc_pid)) {
    LOG(ERROR) << "Failed to get PID of ARC container";
    return false;
  }
  std::string arc_ns;
  if (!context_->GetPidNamespace(arc_pid, &arc_ns)) {
    LOG(ERROR) << "Failed to get PID namespace of ARC container";
    return false;
  }
  std::string ns;
  if (!context_->GetPidNamespace(pid, &ns)) {
    LOG(ERROR) << "Failed to get PID namespace of process";
    return false;
  }
  return ns == arc_ns;
}

bool ArcCollector::HandleJavaCrash(const std::string &crash_type,
                                   const std::string &device,
                                   const std::string &board,
                                   const std::string &cpu_abi) {
  std::string reason;
  const bool should_dump = UserCollectorBase::ShouldDump(
      is_feedback_allowed_function_(), IsDeveloperImage(), &reason);

  std::ostringstream message;
  message << "Received " << crash_type << " notification";

  if (!should_dump) {
    LogCrash(message.str(), reason);
    close(STDIN_FILENO);
    return true;
  }

  std::stringstream stream;
  if (!ReadCrashLogFromStdin(&stream)) {
    LOG(ERROR) << "Failed to read crash log";
    return false;
  }

  CrashLogHeaderMap map;
  std::string exception_info;
  if (!ParseCrashLog(crash_type, &stream, &map, &exception_info)) {
    LOG(ERROR) << "Failed to parse crash log";
    return false;
  }

  const auto exec = GetCrashLogHeader(map, kProcessKey);
  message << " for " << exec;
  LogCrash(message.str(), reason);

  count_crash_function_();

  bool out_of_capacity = false;
  if (!CreateReportForJavaCrash(crash_type, device, board, cpu_abi,
                                map, exception_info, stream.str(),
                                &out_of_capacity)) {
    if (!out_of_capacity)
      EnqueueCollectionErrorLog(0, kErrorSystemIssue, exec);

    return false;
  }

  return true;
}

// static
bool ArcCollector::IsArcRunning() {
  return GetArcPid(nullptr);
}

// static
bool ArcCollector::GetArcPid(pid_t *arc_pid) {
  base::FileEnumerator containers(
      kContainersDir, false, base::FileEnumerator::DIRECTORIES, kArcDirPattern);

  for (FilePath container = containers.Next();
       !container.empty();
       container = containers.Next()) {
    std::string contents;
    if (!ReadFileToString(container.Append(kContainerPid), &contents) ||
        contents.empty())
      continue;

    contents.pop_back();  // Trim EOL.

    pid_t pid;
    if (!base::StringToInt(contents, &pid) ||
        !base::PathExists(GetProcessPath(pid)))
      continue;

    if (arc_pid)
      *arc_pid = pid;

    return true;
  }

  return false;
}

bool ArcCollector::ArcContext::GetArcPid(pid_t *pid) const {
  return ArcCollector::GetArcPid(pid);
}

bool ArcCollector::ArcContext::GetPidNamespace(pid_t pid,
                                               std::string *ns) const {
  const FilePath path = GetProcessPath(pid).Append("ns").Append("pid");

  // The /proc/[pid]/ns/pid file is a special symlink that resolves to a string
  // containing the inode number of the PID namespace, e.g. "pid:[4026531838]".
  FilePath target;
  if (!collector_->GetSymlinkTarget(path, &target))
    return false;

  *ns = target.value();
  return true;
}

bool ArcCollector::ArcContext::GetExeBaseName(pid_t pid,
                                              std::string *exe) const {
  return collector_->CrashCollector::GetExecutableBaseNameFromPid(pid, exe);
}

bool ArcCollector::ArcContext::GetCommand(pid_t pid,
                                          std::string *command) const {
  std::vector<std::string> args = collector_->GetCommandLine(pid);
  if (args.size() == 0)
    return false;
  // Return the command and discard the arguments.
  *command = args[0];
  return true;
}

bool ArcCollector::ArcContext::ReadAuxvForProcess(pid_t pid,
                                                  std::string *contents) const {
  // The architecture with the largest auxv size is powerpc with 400 bytes.
  // Round it up to the next power of two.
  constexpr size_t kMaxAuxvSize = 512;
  const FilePath auxv_path = GetProcessPath(pid).Append("auxv");
  return base::ReadFileToStringWithMaxSize(auxv_path, contents, kMaxAuxvSize);
}

std::string ArcCollector::GetVersion() const {
  std::string version;
  return GetChromeVersion(&version) ? version : kUnknownVersion;
}

bool ArcCollector::GetExecutableBaseNameFromPid(pid_t pid,
                                                std::string *base_name) {
  if (!context_->GetExeBaseName(pid, base_name))
    return false;

  // The runtime for non-native ARC apps overwrites its command line with the
  // package name of the app, so use that instead.
  if (IsArcProcess(pid) && IsAppProcess(*base_name)) {
    if (!context_->GetCommand(pid, base_name))
      LOG(ERROR) << "Failed to get package name";
  }
  return true;
}

bool ArcCollector::ShouldDump(pid_t pid,
                              uid_t uid,
                              const std::string &exec,
                              std::string *reason) {
  if (!IsArcProcess(pid)) {
    *reason = "ignoring - crash origin is not ARC";
    return false;
  }

  if (uid >= kSystemUserEnd) {
    *reason = "ignoring - not a system process";
    return false;
  }

  return UserCollectorBase::ShouldDump(
      is_feedback_allowed_function_(), IsDeveloperImage(), reason);
}

UserCollectorBase::ErrorType ArcCollector::ConvertCoreToMinidump(
    pid_t pid,
    const base::FilePath &container_dir,
    const base::FilePath &core_path,
    const base::FilePath &minidump_path) {
  FilePath root;
  if (!GetArcRoot(&root)) {
    LOG(ERROR) << "Failed to get ARC root";
    return kErrorSystemIssue;
  }

  const char * collector_path = kCoreCollectorPath;
  // TODO(crbug.com/735075): Remove this __WORDSIZE hack by building+installing
  // ARM versions of core_collector{,32}, too.
#if __WORDSIZE == 64
  bool is_64_bit;
  ErrorType elf_class_error = Is64BitProcess(pid, &is_64_bit);
  // Still try to run core_collector32 if 64-bit detection failed.
  if (elf_class_error != kErrorNone || !is_64_bit)
    collector_path = kCoreCollector32Path;
#endif

  ProcessImpl core_collector;
  core_collector.AddArg(collector_path);
  core_collector.AddArg("--minidump");
  core_collector.AddArg(minidump_path.value());
  core_collector.AddArg("--coredump");
  core_collector.AddArg(core_path.value());
  core_collector.AddArg("--proc");
  core_collector.AddArg(container_dir.value());
  core_collector.AddArg("--prefix");
  core_collector.AddArg(root.value());

  std::string error;
  int exit_code = RunAndCaptureOutput(&core_collector, STDERR_FILENO, &error);

  if (exit_code < 0) {
    LOG(ERROR) << "Failed to start " << collector_path;
    return kErrorSystemIssue;
  }

  if (exit_code == EX_OK) {
    std::string process;
    ArcCollector::GetExecutableBaseNameFromPid(pid, &process);
    AddArcMetaData(process, "native_crash", true);
    return kErrorNone;
  }

  std::istringstream in(error);
  std::string line;

  while (std::getline(in, line))
    LOG(ERROR) << line;

  LOG(ERROR) << collector_path << " failed with exit code " << exit_code;
  switch (exit_code) {
    case EX_OSFILE:
      return kErrorInvalidCoreFile;
    case EX_SOFTWARE:
      return kErrorCore2MinidumpConversion;
    default:
      return base::PathExists(core_path) ? kErrorSystemIssue :
                                           kErrorReadCoreData;
  }
}

void ArcCollector::AddArcMetaData(const std::string &process,
                                  const std::string &crash_type,
                                  bool add_arc_properties) {
  AddCrashMetaUploadData(kProductField, kArcProduct);
  AddCrashMetaUploadData(kProcessField, process);
  AddCrashMetaUploadData(kCrashTypeField, crash_type);
  AddCrashMetaUploadData(kChromeOsVersionField, CrashCollector::GetVersion());

  std::string version, device, board, cpu_abi;

  if (add_arc_properties &&
      GetArcProperties(&version, &device, &board, &cpu_abi)) {
    AddCrashMetaUploadData(kArcVersionField, version);
    AddCrashMetaUploadData(kDeviceField, device);
    AddCrashMetaUploadData(kBoardField, board);
    AddCrashMetaUploadData(kCpuAbiField, cpu_abi);
  }

  int64_t start_time;
  brillo::ErrorPtr error;
  SetUpDBus();
  if (session_manager_proxy_->GetArcStartTimeTicks(&start_time, &error)) {
    const uint64_t delta = static_cast<uint64_t>((TimeTicks::Now() -
        TimeTicks::FromInternalValue(start_time)).InSeconds());
    AddCrashMetaUploadData(kUptimeField, FormatDuration(delta));
  } else {
    LOG(ERROR) << "Failed to get ARC uptime: " << error->GetMessage();
  }

  if (IsSilentReport(crash_type))
    AddCrashMetaData(kSilentKey, "true");
}

// static
std::string ArcCollector::GetCrashLogHeader(const CrashLogHeaderMap &map,
                                            const char *key) {
  const auto it = map.find(key);
  return it == map.end() ? "unknown" : it->second;
}

// static
bool ArcCollector::ParseCrashLog(const std::string &type,
                                 std::stringstream *stream,
                                 CrashLogHeaderMap *map,
                                 std::string *exception_info) {
  std::string line;

  // The last header is followed by an empty line.
  while (std::getline(*stream, line) && !line.empty()) {
    const auto end = line.find(':');

    if (end != std::string::npos) {
      const auto begin = line.find_first_not_of(' ', end + 1);

      if (begin != std::string::npos) {
        // TODO(domlaskowski): Use multimap to allow multiple "Package" headers.
        if (!map->emplace(line.substr(0, end), line.substr(begin)).second)
          LOG(WARNING) << "Duplicate header: " << line;
        continue;
      }
    }

    // Ignore malformed headers. The report is still created, but the associated
    // metadata fields are set to "unknown".
    LOG(WARNING) << "Header has unexpected format: " << line;
  }

  if (stream->fail())
    return false;

  if (HasExceptionInfo(type)) {
    std::ostringstream out;
    out << stream->rdbuf();
    *exception_info = out.str();
  }

  return true;
}

bool ArcCollector::CreateReportForJavaCrash(const std::string &crash_type,
                                            const std::string &device,
                                            const std::string &board,
                                            const std::string &cpu_abi,
                                            const CrashLogHeaderMap &map,
                                            const std::string &exception_info,
                                            const std::string &log,
                                            bool *out_of_capacity) {
  FilePath crash_dir;
  if (!GetCreatedCrashDirectoryByEuid(geteuid(), &crash_dir, out_of_capacity)) {
    LOG(ERROR) << "Failed to create or find crash directory";
    return false;
  }

  const auto process = GetCrashLogHeader(map, kProcessKey);

  // FormatDumpBasename relies on the assumption that the combination of process
  // name, timestamp, and PID is unique. This does not hold if a process crashes
  // more than once in the span of a second. While this is improbable for native
  // crashes, Java crashes are not always fatal and may happen in bursts. Hence,
  // ensure uniqueness by replacing the PID with the number of microseconds
  // since the current second.
  const auto now = TimeTicks::Now();
  const pid_t dt = static_cast<pid_t>((now - ToSeconds(now)).InMicroseconds());

  const auto basename = FormatDumpBasename(process, std::time(nullptr), dt);
  const FilePath log_path = GetCrashPath(crash_dir, basename, "log");

  const int size = static_cast<int>(log.size());
  if (WriteNewFile(log_path, log.c_str(), size) != size) {
    PLOG(ERROR) << "Failed to write log";
    return false;
  }

  AddArcMetaData(process, crash_type, false);
  AddCrashMetaUploadData(kArcVersionField, GetCrashLogHeader(map, kBuildKey));
  AddCrashMetaUploadData(kDeviceField, device);
  AddCrashMetaUploadData(kBoardField, board);
  AddCrashMetaUploadData(kCpuAbiField, cpu_abi);

  for (const auto& mapping : kHeaderToFieldMapping) {
    if (map.count(mapping.first)) {
      AddCrashMetaUploadData(mapping.second,
                             GetCrashLogHeader(map, mapping.first));
    }
  }

  if (exception_info.empty()) {
    if (const char * const tag = GetSubjectTag(crash_type)) {
      std::ostringstream out;
      out << '[' << tag << ']';
      const auto it = map.find(kSubjectKey);
      if (it != map.end())
        out << ' ' << it->second;

      AddCrashMetaData(kSignatureField, out.str());
    } else {
      LOG(ERROR) << "Invalid crash type: " << crash_type;
      return false;
    }
  } else {
    const FilePath info_path = GetCrashPath(crash_dir, basename, "info");
    const int size = static_cast<int>(exception_info.size());

    if (WriteNewFile(info_path, exception_info.c_str(), size) != size) {
      PLOG(ERROR) << "Failed to write exception info";
      return false;
    }

    AddCrashMetaUploadText(kExceptionInfoField, info_path.value());
  }

  const FilePath meta_path = GetCrashPath(crash_dir, basename, "meta");
  WriteCrashMetaData(meta_path, process, log_path.value());
  return true;
}

UserCollectorBase::ErrorType ArcCollector::Is64BitProcess(
    int pid, bool *is_64_bit) const {
  std::string auxv_contents;
  if (!context_->ReadAuxvForProcess(pid, &auxv_contents)) {
    PLOG(ERROR) << "Could not read /proc/" << pid << "/auxv";
    return kErrorSystemIssue;
  }
  // auxv is an array of unsigned long[2], and the first element in each entry
  // is an AT_* key. We assume we are running a 32-bit process (hence the
  // |*is_64_bit| below), and then try to see if any of the keys seem off.
  // All AT_* keys are less than ~48, so if we find any key that exceeds 256, we
  // definitely know it is not a 32-bit process. This will almost always trigger
  // correctly because some of the values in the auxv are pointers and their
  // high bits are almost always non-zero. For illustration purposes, consider
  // the following auxv taken from a x86_64 machine:
  //
  // |-------64-bit key------|-----64-bit value------|
  // |32-bit key-|32-bit val-|32-bit key-|32-bit val-|
  //  21 00 00 00 00 00 00 00 00 30 db e6 fe 7f 00 00
  //  10 00 00 00 00 00 00 00 ff fb eb bf 00 00 00 00
  //  06 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00
  //  ...
  //
  //  When interpreted as 64-bit unsigned longs, all the keys are less than 256,
  //  but when interpreted as 32-bit unsigned longs, some of the "keys" will
  //  contain the upper parts of addresses.
  struct Auxv32BitEntry {
    uint32_t key;
    uint32_t value;
  };
  if (auxv_contents.size() % sizeof(Auxv32BitEntry) != 0) {
    LOG(ERROR) << "Could not parse the contents of the auxv file. "
               << "Size not a multiple of 8: " << auxv_contents.size();
    return kErrorSystemIssue;
  }
  *is_64_bit = false;

  const Auxv32BitEntry *auxv_32_bit_entries =
      reinterpret_cast<const Auxv32BitEntry *>(auxv_contents.data());
  const size_t auxv_32_bit_entries_length =
      auxv_contents.size() / sizeof(Auxv32BitEntry);

  for (size_t i = 0; i < auxv_32_bit_entries_length; ++i) {
    if (auxv_32_bit_entries[i].key > 256) {
      *is_64_bit = true;
      break;
    }
  }

  return kErrorNone;
}

namespace {

bool ReadCrashLogFromStdin(std::stringstream *stream) {
  File src(STDIN_FILENO);
  char buffer[kBufferSize];

  while (true) {
    const int count = src.ReadAtCurrentPosNoBestEffort(buffer, kBufferSize);
    if (count < 0)
      return false;

    if (count == 0)
      return stream->tellp() > 0;  // Crash log should not be empty.

    stream->write(buffer, count);
  }
}

bool HasExceptionInfo(const std::string &type) {
  static const std::unordered_set<std::string> kTypes = {
    "data_app_crash",
    "system_app_crash",
    "system_app_wtf",
    "system_server_crash",
    "system_server_wtf"
  };
  return kTypes.count(type);
}

const char *GetSubjectTag(const std::string &type) {
  static const std::unordered_map<std::string, const char *> kTags = {
    { "data_app_native_crash", "native app crash" },
    { "system_app_anr", "ANR" },
    { "system_server_watchdog", "system server watchdog" }
  };

  const auto it = kTags.find(type);
  return it == kTags.cend() ? nullptr : it->second;
}

bool GetChromeVersion(std::string *version) {
  ProcessImpl chrome;
  chrome.AddArg(kChromePath);
  chrome.AddArg("--product-version");

  int exit_code = RunAndCaptureOutput(&chrome, STDOUT_FILENO, version);
  if (exit_code != EX_OK || version->empty()) {
    LOG(ERROR) << "Failed to get Chrome version";
    return false;
  }

  version->pop_back();  // Discard EOL.
  return true;
}

bool GetArcRoot(FilePath *root) {
  base::FileEnumerator containers(
      kContainersDir, false, base::FileEnumerator::DIRECTORIES, kArcDirPattern);

  for (FilePath container = containers.Next();
       !container.empty();
       container = containers.Next()) {
    const FilePath path = container.Append("root");
    if (base::PathExists(path)) {
      *root = path;
      return true;
    }
  }

  return false;
}

bool GetArcProperties(std::string *version,
                      std::string *device,
                      std::string *board,
                      std::string *cpu_abi) {
  FilePath root;
  brillo::KeyValueStore store;
  if (GetArcRoot(&root) &&
      store.Load(root.Append(kArcBuildProp)) &&
      store.GetString(kFingerprintProperty, version) &&
      store.GetString(kDeviceProperty, device) &&
      store.GetString(kBoardProperty, board) &&
      store.GetString(kCpuAbiProperty, cpu_abi))
    return true;

  LOG(ERROR) << "Failed to get ARC properties";
  return false;
}

int RunAndCaptureOutput(ProcessImpl *process, int fd, std::string *output) {
  process->RedirectUsingPipe(fd, false);
  if (process->Start()) {
    const int out = process->GetPipe(fd);
    char buffer[kBufferSize];
    output->clear();

    while (true) {
      const ssize_t count = HANDLE_EINTR(read(out, buffer, kBufferSize));
      if (count < 0) {
        process->Wait();
        break;
      }

      if (count == 0)
        return process->Wait();

      output->append(buffer, count);
    }
  }

  return -1;
}

std::string FormatDuration(uint64_t seconds) {
  constexpr uint64_t kSecondsPerMinute = 60;
  constexpr uint64_t kSecondsPerHour = 60 * kSecondsPerMinute;
  constexpr uint64_t kSecondsPerDay = 24 * kSecondsPerHour;

  const auto days = seconds / kSecondsPerDay;
  seconds %= kSecondsPerDay;
  const auto hours = seconds / kSecondsPerHour;
  seconds %= kSecondsPerHour;
  const auto minutes = seconds / kSecondsPerMinute;
  seconds %= kSecondsPerMinute;

  std::ostringstream out;

  if (days > 0)
    out << days << "d ";
  if (days > 0 || hours > 0)
    out << hours << "h ";
  if (days > 0 || hours > 0 || minutes > 0)
    out << minutes << "min ";

  out << seconds << 's';
  return out.str();
}

}  // namespace
