text: // Copyright 2018 The Chromium 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 "components/crash/core/app/crashpad.h"
  
  #include <dlfcn.h>
  #include <string.h>
  #include <sys/socket.h>
  #include <sys/types.h>
  #include <unistd.h>
  
  #include <algorithm>
  
  #include "base/android/build_info.h"
  #include "base/android/java_exception_reporter.h"
  #include "base/android/jni_android.h"
  #include "base/android/jni_array.h"
  #include "base/android/jni_string.h"
  #include "base/android/path_utils.h"
  #include "base/cxx17_backports.h"
  #include "base/environment.h"
  #include "base/files/file_util.h"
  #include "base/files/scoped_file.h"
  #include "base/logging.h"
  #include "base/macros.h"
  #include "base/no_destructor.h"
  #include "base/path_service.h"
  #include "base/posix/eintr_wrapper.h"
  #include "base/posix/global_descriptors.h"
  #include "base/rand_util.h"
  #include "base/strings/stringprintf.h"
  #include "base/synchronization/lock.h"
  #include "build/branding_buildflags.h"
  #include "build/build_config.h"
  #include "components/crash/android/jni_headers/PackagePaths_jni.h"
  #include "components/crash/core/app/crash_reporter_client.h"
  #include "content/public/common/content_descriptors.h"
  #include "sandbox/linux/services/syscall_wrappers.h"
  #include "third_party/crashpad/crashpad/client/annotation.h"
  #include "third_party/crashpad/crashpad/client/client_argv_handling.h"
  #include "third_party/crashpad/crashpad/client/crashpad_client.h"
  #include "third_party/crashpad/crashpad/client/simulate_crash_linux.h"
  #include "third_party/crashpad/crashpad/snapshot/sanitized/sanitization_information.h"
  #include "third_party/crashpad/crashpad/util/linux/exception_handler_client.h"
  #include "third_party/crashpad/crashpad/util/linux/exception_handler_protocol.h"
  #include "third_party/crashpad/crashpad/util/linux/exception_information.h"
  #include "third_party/crashpad/crashpad/util/linux/scoped_pr_set_dumpable.h"
  #include "third_party/crashpad/crashpad/util/misc/from_pointer_cast.h"
  #include "third_party/crashpad/crashpad/util/posix/signals.h"
  
  namespace crashpad {
  namespace {
  
  class AllowedMemoryRanges {
   public:
    AllowedMemoryRanges() {
      allowed_memory_ranges_.entries = 0;
      allowed_memory_ranges_.size = 0;
    }
  
    AllowedMemoryRanges(const AllowedMemoryRanges&) = delete;
    AllowedMemoryRanges& operator=(const AllowedMemoryRanges&) = delete;
  
    void AddEntry(VMAddress base, VMSize length) {
      SanitizationAllowedMemoryRanges::Range new_entry;
      new_entry.base = base;
      new_entry.length = length;
  
      base::AutoLock lock(lock_);
      std::vector<SanitizationAllowedMemoryRanges::Range> new_array(array_);
      new_array.push_back(new_entry);
      allowed_memory_ranges_.entries =
          FromPointerCast<VMAddress>(new_array.data());
      allowed_memory_ranges_.size += 1;
      array_ = std::move(new_array);
    }
  
    SanitizationAllowedMemoryRanges* GetSanitizationAddress() {
      return &allowed_memory_ranges_;
    }
  
    static AllowedMemoryRanges* Singleton() {
      static base::NoDestructor<AllowedMemoryRanges> singleton;
      return singleton.get();
    }
  
   private:
    base::Lock lock_;
    SanitizationAllowedMemoryRanges allowed_memory_ranges_;
    std::vector<SanitizationAllowedMemoryRanges::Range> array_;
  };
  
  bool SetSanitizationInfo(crash_reporter::CrashReporterClient* client,
                           SanitizationInformation* info) {
    const char* const* allowed_annotations = nullptr;
    void* target_module = nullptr;
    bool sanitize_stacks = false;
    client->GetSanitizationInformation(&allowed_annotations, &target_module,
                                       &sanitize_stacks);
    info->allowed_annotations_address =
        FromPointerCast<VMAddress>(allowed_annotations);
    info->target_module_address = FromPointerCast<VMAddress>(target_module);
    info->allowed_memory_ranges_address = FromPointerCast<VMAddress>(
        AllowedMemoryRanges::Singleton()->GetSanitizationAddress());
    info->sanitize_stacks = sanitize_stacks;
    return allowed_annotations != nullptr || target_module != nullptr ||
           sanitize_stacks;
  }
  
  void SetExceptionInformation(siginfo_t* siginfo,
                               ucontext_t* context,
                               ExceptionInformation* info) {
    info->siginfo_address =
        FromPointerCast<decltype(info->siginfo_address)>(siginfo);
    info->context_address =
        FromPointerCast<decltype(info->context_address)>(context);
    info->thread_id = sandbox::sys_gettid();
  }
  
  void SetClientInformation(ExceptionInformation* exception,
                            SanitizationInformation* sanitization,
                            ExceptionHandlerProtocol::ClientInformation* info) {
    info->exception_information_address =
        FromPointerCast<decltype(info->exception_information_address)>(exception);
  
    info->sanitization_information_address =
        FromPointerCast<decltype(info->sanitization_information_address)>(
            sanitization);
  }
  
  // A signal handler for non-browser processes in the sandbox.
  // Sends a message to a crashpad::CrashHandlerHost to handle the crash.
  class SandboxedHandler {
   public:
    static SandboxedHandler* Get() {
      static SandboxedHandler* instance = new SandboxedHandler();
      return instance;
    }
  
    SandboxedHandler(const SandboxedHandler&) = delete;
    SandboxedHandler& operator=(const SandboxedHandler&) = delete;
  
    bool Initialize(bool dump_at_crash) {
      request_dump_ = dump_at_crash ? 1 : 0;
  
      SetSanitizationInfo(crash_reporter::GetCrashReporterClient(),
                          &sanitization_);
      server_fd_ = base::GlobalDescriptors::GetInstance()->Get(kCrashDumpSignal);
  
      // Android's debuggerd handler on JB MR2 until OREO displays a dialog which
      // is a bad user experience for child process crashes. Disable the debuggerd
      // handler for user builds. crbug.com/273706
      base::android::BuildInfo* build_info =
          base::android::BuildInfo::GetInstance();
      restore_previous_handler_ =
          build_info->sdk_int() < base::android::SDK_VERSION_JELLY_BEAN_MR2 ||
          build_info->sdk_int() >= base::android::SDK_VERSION_OREO ||
          strcmp(build_info->build_type(), "eng") == 0 ||
          strcmp(build_info->build_type(), "userdebug") == 0;
  
      bool signal_stack_initialized =
          CrashpadClient::InitializeSignalStackForThread();
      DCHECK(signal_stack_initialized);
      return Signals::InstallCrashHandlers(HandleCrash, SA_ONSTACK,
                                           &old_actions_);
    }
  
    void HandleCrashNonFatal(int signo, siginfo_t* siginfo, void* context) {
      base::ScopedFD connection;
      if (ConnectToHandler(signo, &connection) == 0) {
        ExceptionInformation exception_information;
        SetExceptionInformation(siginfo, static_cast<ucontext_t*>(context),
                                &exception_information);
  
        ExceptionHandlerProtocol::ClientInformation info;
        SetClientInformation(&exception_information, &sanitization_, &info);
  
        ScopedPrSetDumpable set_dumpable(/* may_log= */ false);
  
        ExceptionHandlerClient handler_client(connection.get(), false);
        handler_client.SetCanSetPtracer(false);
        handler_client.RequestCrashDump(info);
      }
    }
  
   private:
    SandboxedHandler() = default;
    ~SandboxedHandler() = delete;
  
    int ConnectToHandler(int signo, base::ScopedFD* connection) {
      int fds[2];
      if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
        return errno;
      }
      base::ScopedFD local_connection(fds[0]);
      base::ScopedFD handlers_socket(fds[1]);
  
      // SELinux may block the handler from setting SO_PASSCRED on this socket.
      // Attempt to set it here, but the handler can still try if this fails.
      int optval = 1;
      socklen_t optlen = sizeof(optval);
      setsockopt(handlers_socket.get(), SOL_SOCKET, SO_PASSCRED, &optval, optlen);
  
      iovec iov[2];
      iov[0].iov_base = &signo;
      iov[0].iov_len = sizeof(signo);
      iov[1].iov_base = &request_dump_;
      iov[1].iov_len = sizeof(request_dump_);
  
      msghdr msg;
      msg.msg_name = nullptr;
      msg.msg_namelen = 0;
      msg.msg_iov = iov;
      msg.msg_iovlen = base::size(iov);
  
      char cmsg_buf[CMSG_SPACE(sizeof(int))];
      msg.msg_control = cmsg_buf;
      msg.msg_controllen = sizeof(cmsg_buf);
  
      cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
      cmsg->cmsg_level = SOL_SOCKET;
      cmsg->cmsg_type = SCM_RIGHTS;
      cmsg->cmsg_len = CMSG_LEN(sizeof(int));
      *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = handlers_socket.get();
  
      if (HANDLE_EINTR(sendmsg(server_fd_, &msg, MSG_NOSIGNAL)) < 0) {
        return errno;
      }
  
      *connection = std::move(local_connection);
      return 0;
    }
  
    static void HandleCrash(int signo, siginfo_t* siginfo, void* context) {
      SandboxedHandler* state = Get();
      state->HandleCrashNonFatal(signo, siginfo, context);
      Signals::RestoreHandlerAndReraiseSignalOnReturn(
          siginfo, state->restore_previous_handler_
                       ? state->old_actions_.ActionForSignal(signo)
                       : nullptr);
    }
  
    Signals::OldActions old_actions_ = {};
    SanitizationInformation sanitization_;
    int server_fd_;
    unsigned char request_dump_;
  
    // true if the previously installed signal handler is restored after
    // handling a crash. Otherwise SIG_DFL is restored.
    bool restore_previous_handler_;
  };
  
  }  // namespace
  }  // namespace crashpad
  
  namespace crash_reporter {
  namespace {
  
  void SetJavaExceptionInfo(const char* info_string) {
    static crashpad::StringAnnotation<5 * 4096> exception_info("exception_info");
    if (info_string) {
      exception_info.Set(info_string);
    } else {
      exception_info.Clear();
    }
  }
  
  void SetBuildInfoAnnotations(std::map<std::string, std::string>* annotations) {
    base::android::BuildInfo* info = base::android::BuildInfo::GetInstance();
  
    (*annotations)["android_build_id"] = info->android_build_id();
    (*annotations)["android_build_fp"] = info->android_build_fp();
    (*annotations)["sdk"] = base::StringPrintf("%d", info->sdk_int());
    (*annotations)["device"] = info->device();
    (*annotations)["model"] = info->model();
    (*annotations)["brand"] = info->brand();
    (*annotations)["board"] = info->board();
    (*annotations)["installer_package_name"] = info->installer_package_name();
    (*annotations)["abi_name"] = info->abi_name();
    (*annotations)["custom_themes"] = info->custom_themes();
    (*annotations)["resources_version"] = info->resources_version();
    (*annotations)["gms_core_version"] = info->gms_version_code();
  
    if (info->firebase_app_id()[0] != '\0') {
      (*annotations)["package"] = std::string(info->firebase_app_id()) + " v" +
                                  info->package_version_code() + " (" +
                                  info->package_version_name() + ")";
    }
  }
  
  // Constructs paths to a handler trampoline executable and a library exporting
  // the symbol `CrashpadHandlerMain()`. This requires this function to be built
  // into the same object exporting this symbol and the handler trampoline is
  // adjacent to it.
  bool GetHandlerTrampoline(std::string* handler_trampoline,
                            std::string* handler_library) {
    // The linker doesn't support loading executables passed on its command
    // line until Q.
    if (base::android::BuildInfo::GetInstance()->sdk_int() <
        base::android::SDK_VERSION_Q) {
      return false;
    }
  
    Dl_info info;
    if (dladdr(reinterpret_cast<void*>(&GetHandlerTrampoline), &info) == 0 ||
        dlsym(dlopen(info.dli_fname, RTLD_NOLOAD | RTLD_LAZY),
              "CrashpadHandlerMain") == nullptr) {
      return false;
    }
  
    std::string local_handler_library(info.dli_fname);
  
    size_t libdir_end = local_handler_library.rfind('/');
    if (libdir_end == std::string::npos) {
      return false;
    }
  
    std::string local_handler_trampoline(local_handler_library, 0,
                                         libdir_end + 1);
    local_handler_trampoline += "libcrashpad_handler_trampoline.so";
  
    handler_trampoline->swap(local_handler_trampoline);
    handler_library->swap(local_handler_library);
    return true;
  }
  
  #if defined(__arm__) && defined(__ARM_ARCH_7A__)
  #define CURRENT_ABI "armeabi-v7a"
  #elif defined(__arm__)
  #define CURRENT_ABI "armeabi"
  #elif defined(__i386__)
  #define CURRENT_ABI "x86"
  #elif defined(__mips__)
  #define CURRENT_ABI "mips"
  #elif defined(__x86_64__)
  #define CURRENT_ABI "x86_64"
  #elif defined(__aarch64__)
  #define CURRENT_ABI "arm64-v8a"
  #else
  #error "Unsupported target abi"
  #endif
  
  void MakePackagePaths(std::string* classpath, std::string* libpath) {
    JNIEnv* env = base::android::AttachCurrentThread();
  
    base::android::ScopedJavaLocalRef<jstring> arch =
        base::android::ConvertUTF8ToJavaString(env,
                                               base::StringPiece(CURRENT_ABI));
    base::android::ScopedJavaLocalRef<jobjectArray> paths =
        Java_PackagePaths_makePackagePaths(env, arch);
  
    base::android::ConvertJavaStringToUTF8(
        env, static_cast<jstring>(env->GetObjectArrayElement(paths.obj(), 0)),
        classpath);
    base::android::ConvertJavaStringToUTF8(
        env, static_cast<jstring>(env->GetObjectArrayElement(paths.obj(), 1)),
        libpath);
  }
  
  // Copies and extends the current environment with CLASSPATH and LD_LIBRARY_PATH
  // set to library paths in the APK.
  bool BuildEnvironmentWithApk(bool use_64_bit,
                               std::vector<std::string>* result) {
    DCHECK(result->empty());
  
    std::string classpath;
    std::string library_path;
    MakePackagePaths(&classpath, &library_path);
  
    std::unique_ptr<base::Environment> env(base::Environment::Create());
    static constexpr char kClasspathVar[] = "CLASSPATH";
    std::string current_classpath;
    env->GetVar(kClasspathVar, &current_classpath);
    classpath += ":" + current_classpath;
  
    static constexpr char kLdLibraryPathVar[] = "LD_LIBRARY_PATH";
    std::string current_library_path;
    env->GetVar(kLdLibraryPathVar, &current_library_path);
    library_path += ":" + current_library_path;
  
    static constexpr char kRuntimeRootVar[] = "ANDROID_RUNTIME_ROOT";
    std::string runtime_root;
    if (env->GetVar(kRuntimeRootVar, &runtime_root)) {
      library_path += ":" + runtime_root + (use_64_bit ? "/lib64" : "/lib");
    }
  
    result->push_back("CLASSPATH=" + classpath);
    result->push_back("LD_LIBRARY_PATH=" + library_path);
    for (char** envp = environ; *envp != nullptr; ++envp) {
      if ((strncmp(*envp, kClasspathVar, strlen(kClasspathVar)) == 0 &&
           (*envp)[strlen(kClasspathVar)] == '=') ||
          (strncmp(*envp, kLdLibraryPathVar, strlen(kLdLibraryPathVar)) == 0 &&
           (*envp)[strlen(kLdLibraryPathVar)] == '=')) {
        continue;
      }
      result->push_back(*envp);
    }
  
    return true;
  }
  
  const char kCrashpadJavaMain[] =
      "org.chromium.components.crash.browser.CrashpadMain";
  
  void BuildHandlerArgs(CrashReporterClient* crash_reporter_client,
                        base::FilePath* database_path,
                        base::FilePath* metrics_path,
                        std::string* url,
                        std::map<std::string, std::string>* process_annotations,
                        std::vector<std::string>* arguments) {
    crash_reporter_client->GetCrashDumpLocation(database_path);
    crash_reporter_client->GetCrashMetricsLocation(metrics_path);
  
    // TODO(jperaza): Set URL for Android when Crashpad takes over report upload.
    *url = std::string();
  
    std::string product_name;
    std::string product_version;
    std::string channel;
    crash_reporter_client->GetProductNameAndVersion(&product_name,
                                                    &product_version, &channel);
    (*process_annotations)["prod"] = product_name;
    (*process_annotations)["ver"] = product_version;
  
    SetBuildInfoAnnotations(process_annotations);
  
  #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
    // Empty means stable.
    const bool allow_empty_channel = true;
  #else
    const bool allow_empty_channel = false;
  #endif
    if (allow_empty_channel || !channel.empty()) {
      (*process_annotations)["channel"] = channel;
    }
  
    (*process_annotations)["plat"] = std::string("Android");
  }
  
  bool ShouldHandleCrashAndUpdateArguments(bool write_minidump_to_database,
                                           bool write_minidump_to_log,
                                           std::vector<std::string>* arguments) {
    if (!write_minidump_to_database)
      arguments->push_back("--no-write-minidump-to-database");
    if (write_minidump_to_log)
      arguments->push_back("--write-minidump-to-log");
    return write_minidump_to_database || write_minidump_to_log;
  }
  
  bool GetHandlerPath(base::FilePath* exe_dir, base::FilePath* handler_path) {
    // There is not any normal way to package native executables in an Android
    // APK. The Crashpad handler is packaged like a loadable module, which
    // Android's APK installer expects to be named like a shared library, but it
    // is in fact a standalone executable.
    if (!base::PathService::Get(base::DIR_MODULE, exe_dir)) {
      return false;
    }
    *handler_path = exe_dir->Append("libchrome_crashpad_handler.so");
    return true;
  }
  
  bool SetLdLibraryPath(const base::FilePath& lib_path) {
  #if defined(COMPONENT_BUILD)
    std::string library_path(lib_path.value());
  
    static constexpr char kLibraryPathVar[] = "LD_LIBRARY_PATH";
    std::unique_ptr<base::Environment> env(base::Environment::Create());
    std::string old_path;
    if (env->GetVar(kLibraryPathVar, &old_path)) {
      library_path.push_back(':');
      library_path.append(old_path);
    }
  
    if (!env->SetVar(kLibraryPathVar, library_path)) {
      return false;
    }
  #endif
  
    return true;
  }
  
  class HandlerStarter {
    // TODO(jperaza): Currently only launching a same-bitness handler is
    // supported. The logic to build package paths, locate a handler executable,
    // and the crashpad client interface for launching a Java handler need to be
    // updated to use a specified bitness before a cross-bitness handler can be
    // used.
  #if defined(ARCH_CPU_64_BITS)
    static constexpr bool kUse64Bit = true;
  #else
    static constexpr bool kUse64Bit = false;
  #endif
  
   public:
    static HandlerStarter* Get() {
      static HandlerStarter* instance = new HandlerStarter();
      return instance;
    }
  
    HandlerStarter(const HandlerStarter&) = delete;
    HandlerStarter& operator=(const HandlerStarter&) = delete;
  
    base::FilePath Initialize(bool dump_at_crash) {
      base::FilePath database_path;
      base::FilePath metrics_path;
      std::string url;
      std::map<std::string, std::string> process_annotations;
      std::vector<std::string> arguments;
      BuildHandlerArgs(GetCrashReporterClient(), &database_path, &metrics_path,
                       &url, &process_annotations, &arguments);
  
      base::FilePath exe_dir;
      base::FilePath handler_path;
      if (!GetHandlerPath(&exe_dir, &handler_path)) {
        return database_path;
      }
  
      if (crashpad::SetSanitizationInfo(GetCrashReporterClient(),
                                        &browser_sanitization_info_)) {
        arguments.push_back(base::StringPrintf("--sanitization-information=%p",
                                               &browser_sanitization_info_));
      }
  
      std::string browser_ptype;
      if (GetCrashReporterClient()->GetBrowserProcessType(&browser_ptype)) {
        process_annotations["ptype"] = browser_ptype;
      }
  
      // Don't handle SIGQUIT in the browser process on Android; the system masks
      // this and uses it for generating ART stack traces, and if it gets unmasked
      // (e.g. by a WebView app) we don't want to treat this as a crash.
      GetCrashpadClient().SetUnhandledSignals({SIGQUIT});
  
      if (!base::PathExists(handler_path)) {
        use_java_handler_ =
            !GetHandlerTrampoline(&handler_trampoline_, &handler_library_);
      }
  
      if (!ShouldHandleCrashAndUpdateArguments(
              dump_at_crash, GetCrashReporterClient()->ShouldWriteMinidumpToLog(),
              &arguments)) {
        return database_path;
      }
  
      if (use_java_handler_ || !handler_trampoline_.empty()) {
        std::vector<std::string> env;
        if (!BuildEnvironmentWithApk(kUse64Bit, &env)) {
          return database_path;
        }
  
        bool result = use_java_handler_
                          ? GetCrashpadClient().StartJavaHandlerAtCrash(
                                kCrashpadJavaMain, &env, database_path,
                                metrics_path, url, process_annotations, arguments)
                          : GetCrashpadClient().StartHandlerWithLinkerAtCrash(
                                handler_trampoline_, handler_library_, kUse64Bit,
                                &env, database_path, metrics_path, url,
                                process_annotations, arguments);
        DCHECK(result);
        return database_path;
      }
  
      if (!SetLdLibraryPath(exe_dir)) {
        return database_path;
      }
  
      bool result = GetCrashpadClient().StartHandlerAtCrash(
          handler_path, database_path, metrics_path, url, process_annotations,
          arguments);
      DCHECK(result);
      return database_path;
    }
  
    bool StartHandlerForClient(CrashReporterClient* client,
                               int fd,
                               bool write_minidump_to_database) {
      base::FilePath database_path;
      base::FilePath metrics_path;
      std::string url;
      std::map<std::string, std::string> process_annotations;
      std::vector<std::string> arguments;
      BuildHandlerArgs(client, &database_path, &metrics_path, &url,
                       &process_annotations, &arguments);
  
      base::FilePath exe_dir;
      base::FilePath handler_path;
      if (!GetHandlerPath(&exe_dir, &handler_path)) {
        return false;
      }
  
      if (!ShouldHandleCrashAndUpdateArguments(write_minidump_to_database,
                                               client->ShouldWriteMinidumpToLog(),
                                               &arguments)) {
        return true;
      }
  
      if (use_java_handler_ || !handler_trampoline_.empty()) {
        std::vector<std::string> env;
        if (!BuildEnvironmentWithApk(kUse64Bit, &env)) {
          return false;
        }
  
        bool result =
            use_java_handler_
                ? GetCrashpadClient().StartJavaHandlerForClient(
                      kCrashpadJavaMain, &env, database_path, metrics_path, url,
                      process_annotations, arguments, fd)
                : GetCrashpadClient().StartHandlerWithLinkerForClient(
                      handler_trampoline_, handler_library_, kUse64Bit, &env,
                      database_path, metrics_path, url, process_annotations,
                      arguments, fd);
        return result;
      }
  
      if (!SetLdLibraryPath(exe_dir)) {
        return false;
      }
  
      return GetCrashpadClient().StartHandlerForClient(
          handler_path, database_path, metrics_path, url, process_annotations,
          arguments, fd);
    }
  
   private:
    HandlerStarter() = default;
    ~HandlerStarter() = delete;
  
    crashpad::SanitizationInformation browser_sanitization_info_;
    std::string handler_trampoline_;
    std::string handler_library_;
    bool use_java_handler_ = false;
  };
  
  bool ConnectToHandler(CrashReporterClient* client, base::ScopedFD* connection) {
    int fds[2];
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
      PLOG(ERROR) << "socketpair";
      return false;
    }
    base::ScopedFD local_connection(fds[0]);
    base::ScopedFD handlers_socket(fds[1]);
  
    if (!HandlerStarter::Get()->StartHandlerForClient(
            client, handlers_socket.get(),
            true /* write_minidump_to_database */)) {
      return false;
    }
  
    *connection = std::move(local_connection);
    return true;
  }
  
  bool g_is_browser = false;
  
  }  // namespace
  
  // TODO(jperaza): This might be simplified to have both the browser and child
  // processes use CRASHPAD_SIMULATE_CRASH() if CrashpadClient allows injecting
  // the Chromium specific SandboxedHandler.
  void DumpWithoutCrashing() {
    if (g_is_browser) {
      CRASHPAD_SIMULATE_CRASH();
    } else {
      siginfo_t siginfo;
      siginfo.si_signo = crashpad::Signals::kSimulatedSigno;
      siginfo.si_errno = 0;
      siginfo.si_code = 0;
  
      ucontext_t context;
      crashpad::CaptureContext(&context);
  
      crashpad::SandboxedHandler::Get()->HandleCrashNonFatal(siginfo.si_signo,
                                                             &siginfo, &context);
    }
  }
  
  bool DumpWithoutCrashingForClient(CrashReporterClient* client) {
    base::ScopedFD connection;
    if (!ConnectToHandler(client, &connection)) {
      return false;
    }
  
    siginfo_t siginfo;
    siginfo.si_signo = crashpad::Signals::kSimulatedSigno;
    siginfo.si_errno = 0;
    siginfo.si_code = 0;
  
    ucontext_t context;
    crashpad::CaptureContext(&context);
  
    crashpad::SanitizationInformation sanitization;
    crashpad::SetSanitizationInfo(client, &sanitization);
  
    crashpad::ExceptionInformation exception;
    crashpad::SetExceptionInformation(&siginfo, &context, &exception);
  
    crashpad::ExceptionHandlerProtocol::ClientInformation info;
    crashpad::SetClientInformation(&exception, &sanitization, &info);
  
    crashpad::ScopedPrSetDumpable set_dumpable(/* may_log= */ false);
  
    crashpad::ExceptionHandlerClient handler_client(connection.get(), false);
    return handler_client.RequestCrashDump(info) == 0;
  }
  
  void AllowMemoryRange(void* begin, size_t length) {
    crashpad::AllowedMemoryRanges::Singleton()->AddEntry(
        crashpad::FromPointerCast<crashpad::VMAddress>(begin),
        static_cast<crashpad::VMSize>(length));
  }
  
  namespace internal {
  
  bool StartHandlerForClient(int fd, bool write_minidump_to_database) {
    return HandlerStarter::Get()->StartHandlerForClient(
        GetCrashReporterClient(), fd, write_minidump_to_database);
  }
  
  base::FilePath PlatformCrashpadInitialization(
      bool initial_client,
      bool browser_process,
      bool embedded_handler,
      const std::string& user_data_dir,
      const base::FilePath& exe_path,
      const std::vector<std::string>& initial_arguments) {
    DCHECK_EQ(initial_client, browser_process);
    DCHECK(initial_arguments.empty());
  
    // Not used on Android.
    DCHECK(!embedded_handler);
    DCHECK(exe_path.empty());
  
    g_is_browser = browser_process;
  
    bool dump_at_crash = true;
    base::android::SetJavaExceptionCallback(SetJavaExceptionInfo);
  
    unsigned int dump_percentage =
        GetCrashReporterClient()->GetCrashDumpPercentage();
    if (dump_percentage < 100 &&
        static_cast<unsigned int>(base::RandInt(0, 99)) >= dump_percentage) {
      dump_at_crash = false;
    }
  
    if (browser_process) {
      HandlerStarter* starter = HandlerStarter::Get();
      return starter->Initialize(dump_at_crash);
    }
  
    crashpad::SandboxedHandler* handler = crashpad::SandboxedHandler::Get();
    bool result = handler->Initialize(dump_at_crash);
    DCHECK(result);
  
    return base::FilePath();
  }
  
  }  // namespace internal
  
  }  // namespace crash_reporter
  