// Copyright 2018 The Chromium Authors
// 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 <string_view>

#include "base/android/android_info.h"
#include "base/android/apk_info.h"
#include "base/android/device_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/compiler_specific.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.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/core/app/crash_reporter_client.h"
#include "content/public/common/content_descriptors.h"
#include "partition_alloc/buildflags.h"
#include "partition_alloc/tagging.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/crashpad_info.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"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/crash/android/package_paths_jni/PackagePaths_jni.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
    restore_previous_handler_ =
        base::android::android_info::sdk_int() >=
            base::android::android_info::SDK_VERSION_OREO ||
        base::android::android_info::build_type() == "eng" ||
        base::android::android_info::build_type() == "userdebug";

    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);
    }
  }

  using CrashHandlerFunc = bool (*)(int, siginfo_t*, ucontext_t*);
  void SetLastChanceExceptionHandler(CrashHandlerFunc handler) {
    last_chance_handler_ = handler;
  }

 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 = std::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*>(UNSAFE_TODO(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);
    if (state->last_chance_handler_ &&
        state->last_chance_handler_(signo, siginfo,
                                    static_cast<ucontext_t*>(context))) {
      return;
    }
    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_;
  CrashHandlerFunc last_chance_handler_;

  // 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) {
  (*annotations)["android_build_id"] =
      base::android::android_info::android_build_id();
  (*annotations)["android_build_fp"] =
      base::android::android_info::android_build_fp();
  (*annotations)["sdk"] =
      base::StringPrintf("%d", base::android::android_info::sdk_int());
  (*annotations)["device"] = base::android::android_info::device();
  (*annotations)["model"] = base::android::android_info::model();
  (*annotations)["brand"] = base::android::android_info::brand();
  (*annotations)["board"] = base::android::android_info::board();
  (*annotations)["installer_package_name"] =
      base::android::apk_info::installer_package_name();
  (*annotations)["abi_name"] = base::android::android_info::abi_name();
  (*annotations)["resources_version"] =
      base::android::apk_info::resources_version();
  (*annotations)["gms_core_version"] =
      base::android::device_info::gms_version_code();

  (*annotations)["package"] =
      std::string(base::android::apk_info::package_name()) + " v" +
      base::android::apk_info::package_version_code() + " (" +
      base::android::apk_info::package_version_name() + ")";
}



#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"
#elif defined(__riscv) && (__riscv_xlen == 64)
#define CURRENT_ABI "riscv64"
#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,
                                             std::string_view(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);
}



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();

  ProductInfo product_info;
  crash_reporter_client->GetProductInfo(&product_info);
  (*process_annotations)["prod"] = product_info.product_name;
  (*process_annotations)["ver"] = product_info.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 || !product_info.channel.empty()) {
    (*process_annotations)["channel"] = product_info.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;
}

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);

    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});

    internal::GetHandlerTrampoline(&handler_trampoline_, &handler_library_);

    if (!ShouldHandleCrashAndUpdateArguments(
            dump_at_crash, GetCrashReporterClient()->ShouldWriteMinidumpToLog(),
            &arguments)) {
      return database_path;
    }

    if (!handler_trampoline_.empty()) {
      std::vector<std::string> env;
      if (!internal::BuildEnvironmentWithApk(kUse64Bit, &env)) {
        return database_path;
      }

      bool result = GetCrashpadClient().StartHandlerWithLinkerAtCrash(
          handler_trampoline_, handler_library_, kUse64Bit, &env, database_path,
          metrics_path, url, process_annotations, arguments);
      DCHECK(result);
      return database_path;
    }

    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);

    if (!ShouldHandleCrashAndUpdateArguments(write_minidump_to_database,
                                             client->ShouldWriteMinidumpToLog(),
                                             &arguments)) {
      return true;
    }

    if (!handler_trampoline_.empty()) {
      std::vector<std::string> env;
      if (!internal::BuildEnvironmentWithApk(kUse64Bit, &env)) {
        return false;
      }

      return GetCrashpadClient().StartHandlerWithLinkerForClient(
          handler_trampoline_, handler_library_, kUse64Bit, &env, database_path,
          metrics_path, url, process_annotations, arguments, fd);
    }

    return false;
  }

 private:
  HandlerStarter() = default;
  ~HandlerStarter() = delete;

  crashpad::SanitizationInformation browser_sanitization_info_;
  std::string handler_trampoline_;
  std::string handler_library_;
};

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);
  }
}

void AllowMemoryRange(void* begin, size_t length) {
  crashpad::AllowedMemoryRanges::Singleton()->AddEntry(
      crashpad::FromPointerCast<crashpad::VMAddress>(begin),
      static_cast<crashpad::VMSize>(length));
}

namespace internal {

bool GetHandlerTrampoline(std::string* handler_trampoline,
                          std::string* handler_library) {
  Dl_info info;
  CHECK(dladdr(reinterpret_cast<void*>(&GetHandlerTrampoline), &info));
  std::string local_handler_library(info.dli_fname);

  // We'll just fail when launching the handler if this fails, but nicer to
  // catch it early when DCHECK_IS_ON().
#if DCHECK_IS_ON()
  void* handle = dlopen(info.dli_fname, RTLD_NOLOAD | RTLD_LAZY);
  bool has_main = dlsym(handle, "CrashpadHandlerMain") != nullptr;
  dlclose(handle);
  if (!has_main) {
    NOTREACHED() << local_handler_library << " is missing CrashpadHandlerMain";
  }
#endif

  base::FilePath handler_library_path(info.dli_fname);
  base::FilePath libdir = handler_library_path.DirName();
  base::FilePath handler_trampoline_path =
      libdir.AppendASCII("libcrashpad_handler_trampoline.so");

  *handler_trampoline = handler_trampoline_path.value();
  *handler_library = handler_library_path.value();
  return true;
}

bool BuildEnvironmentWithApk(bool use_64_bit,
                             std::vector<std::string>* result) {
  DCHECK(result->empty());

  std::string classpath;
  std::string library_path;
  // CLASSPATH can just inherit existing values once Trichrome is removed.
  MakePackagePaths(&classpath, &library_path);

  std::unique_ptr<base::Environment> env(base::Environment::Create());
  static constexpr char kClasspathVar[] = "CLASSPATH";
  std::optional<std::string> current_classpath = env->GetVar(kClasspathVar);
  if (current_classpath.has_value()) {
    classpath += ":" + current_classpath.value();
  }

  static constexpr char kLdLibraryPathVar[] = "LD_LIBRARY_PATH";
  std::optional<std::string> current_library_path =
      env->GetVar(kLdLibraryPathVar);
  if (current_library_path.has_value()) {
    library_path += ":" + current_library_path.value();
  }

  static constexpr char kRuntimeRootVar[] = "ANDROID_RUNTIME_ROOT";
  std::optional<std::string> runtime_root = env->GetVar(kRuntimeRootVar);
  if (runtime_root.has_value()) {
    library_path +=
        ":" + runtime_root.value() + (use_64_bit ? "/lib64" : "/lib");
  }

  result->push_back("CLASSPATH=" + classpath);
  result->push_back("LD_LIBRARY_PATH=" + library_path);
  for (char** envp = environ; *envp != nullptr; UNSAFE_TODO(++envp)) {
    if ((UNSAFE_TODO(strncmp(*envp, kClasspathVar, strlen(kClasspathVar))) ==
             0 &&
         UNSAFE_TODO((*envp)[strlen(kClasspathVar)]) == '=') ||
        (UNSAFE_TODO(strncmp(*envp, kLdLibraryPathVar,
                             strlen(kLdLibraryPathVar))) == 0 &&
         UNSAFE_TODO((*envp)[strlen(kLdLibraryPathVar)]) == '=')) {
      continue;
    }
    result->push_back(*envp);
  }

  return true;
}

bool StartHandlerForClient(int fd, bool write_minidump_to_database) {
  return HandlerStarter::Get()->StartHandlerForClient(
      GetCrashReporterClient(), fd, write_minidump_to_database);
}

bool 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,
    const std::vector<base::FilePath>& attachments,
    base::FilePath* database_path) {
  DCHECK_EQ(initial_client, browser_process);
  DCHECK(initial_arguments.empty());
  DCHECK(attachments.empty());

  // Not used on Android.
  DCHECK(!embedded_handler);
  DCHECK(exe_path.empty());

  g_is_browser = browser_process;

  base::android::SetJavaExceptionCallback(SetJavaExceptionInfo);

  CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
  bool dump_at_crash = true;
  unsigned int dump_percentage =
      crash_reporter_client->GetCrashDumpPercentage();
  if (dump_percentage < 100 && static_cast<unsigned int>(base::RandIntInclusive(
                                   0, 99)) >= dump_percentage) {
    dump_at_crash = false;
  }

  // In the not-large-dumps case, record enough extra memory to be able to save
  // dereferenced memory from all registers on the crashing thread. Crashpad may
  // save 512-bytes per register, and the largest register set (not including
  // stack pointers) is ARM64 with 32 registers. Hence, 16 KiB.
  const uint32_t indirect_memory_limit =
      crash_reporter_client->GetShouldDumpLargerDumps() ? 4 * 1024 * 1024
                                                        : 16 * 1024;
  crashpad::CrashpadInfo::GetCrashpadInfo()
      ->set_gather_indirectly_referenced_memory(crashpad::TriState::kEnabled,
                                                indirect_memory_limit);

  if (browser_process) {
    HandlerStarter* starter = HandlerStarter::Get();
    *database_path = starter->Initialize(dump_at_crash);
#if PA_BUILDFLAG(HAS_MEMORY_TAGGING)
    // Handler gets called in SignalHandler::HandleOrReraiseSignal() after
    // reporting the crash.
    crashpad::CrashpadClient::SetLastChanceExceptionHandler(
        partition_alloc::PermissiveMte::HandleCrash);
#endif  // PA_BUILDFLAG(HAS_MEMORY_TAGGING)
    return true;
  }

  crashpad::SandboxedHandler* handler = crashpad::SandboxedHandler::Get();
  bool result = handler->Initialize(dump_at_crash);
  DCHECK(result);

#if PA_BUILDFLAG(HAS_MEMORY_TAGGING)
  handler->SetLastChanceExceptionHandler(
      partition_alloc::PermissiveMte::HandleCrash);
#endif  // PA_BUILDFLAG(HAS_MEMORY_TAGGING)

  *database_path = base::FilePath();
  return true;
}

}  // namespace internal

}  // namespace crash_reporter

DEFINE_JNI(PackagePaths)
