mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-08 21:26:04 +00:00
android: Add client methods to start a Java handler
These methods use /system/bin/app_process{32,64} to load a Java class supplied by the embedding application. It is expected that the supplied class loads a native library containing Crashpad's handler code and passes its arguments to crashpad::HandlerMain(). Bug: crashpad:30 Change-Id: Ic0f9a1439007047b06f07f5ec7d5de9a9d4a19a2 Reviewed-on: https://chromium-review.googlesource.com/1194400 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
0204fbd38b
commit
d4d2f8557a
@ -61,14 +61,14 @@ std::vector<std::string> BuildHandlerArgvStrings(
|
||||
return argv_strings;
|
||||
}
|
||||
|
||||
void ConvertArgvStrings(const std::vector<std::string>& argv_strings,
|
||||
std::vector<const char*>* argv) {
|
||||
argv->clear();
|
||||
argv->reserve(argv_strings.size() + 1);
|
||||
for (const auto& arg : argv_strings) {
|
||||
argv->push_back(arg.c_str());
|
||||
void StringVectorToCStringVector(const std::vector<std::string>& strings,
|
||||
std::vector<const char*>* c_strings) {
|
||||
c_strings->clear();
|
||||
c_strings->reserve(strings.size() + 1);
|
||||
for (const auto& str : strings) {
|
||||
c_strings->push_back(str.c_str());
|
||||
}
|
||||
argv->push_back(nullptr);
|
||||
c_strings->push_back(nullptr);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -40,11 +40,11 @@ std::vector<std::string> BuildHandlerArgvStrings(
|
||||
//! \brief Flattens a string vector into a const char* vector suitable for use
|
||||
//! in an exec() call.
|
||||
//!
|
||||
//! \param[in] argv_strings Arguments to be passed to child process, typically
|
||||
//! created by BuildHandlerArgvStrings().
|
||||
//! \param[out] argv argv suitable for starting the child process.
|
||||
void ConvertArgvStrings(const std::vector<std::string>& argv_strings,
|
||||
std::vector<const char*>* argv);
|
||||
//! \param[in] strings A vector of string data. This vector must remain valid
|
||||
//! for the lifetime of \a c_strings.
|
||||
//! \param[out] c_strings A vector of pointers to the string data in \a strings.
|
||||
void StringVectorToCStringVector(const std::vector<std::string>& strings,
|
||||
std::vector<const char*>* c_strings);
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
|
@ -112,6 +112,84 @@ class CrashpadClient {
|
||||
bool restartable,
|
||||
bool asynchronous_start);
|
||||
|
||||
#if defined(OS_ANDROID) || DOXYGEN
|
||||
//! \brief Installs a signal handler to execute `/system/bin/app_process` and
|
||||
//! load a Java class in response to a crash.
|
||||
//!
|
||||
//! \param[in] class_name The fully qualified class name to load, which must
|
||||
//! define a `main()` method to be invoked by `app_process`. Arguments
|
||||
//! will be passed to this method as though it were the Crashpad handler.
|
||||
//! This class is expected to load a native library defining
|
||||
//! crashpad::HandlerMain() and pass the arguments to it.
|
||||
//! \param[in] env A vector of environment variables of the form `var=value`
|
||||
//! defining the environment in which to execute `app_process`. If this
|
||||
//! value is `nullptr`, the application's environment at the time of the
|
||||
//! crash will be used.
|
||||
//! \param[in] database The path to a Crashpad database. The handler will be
|
||||
//! started with this path as its `--database` argument.
|
||||
//! \param[in] metrics_dir The path to an already existing directory where
|
||||
//! metrics files can be stored. The handler will be started with this
|
||||
//! path as its `--metrics-dir` argument.
|
||||
//! \param[in] url The URL of an upload server. The handler will be started
|
||||
//! with this URL as its `--url` argument.
|
||||
//! \param[in] annotations Process annotations to set in each crash report.
|
||||
//! The handler will be started with an `--annotation` argument for each
|
||||
//! element in this map.
|
||||
//! \param[in] arguments Additional arguments to pass to the Crashpad handler.
|
||||
//! Arguments passed in other parameters and arguments required to perform
|
||||
//! the handshake are the responsibility of this method, and must not be
|
||||
//! specified in this parameter.
|
||||
//!
|
||||
//! \return `true` on success, `false` on failure with a message logged.
|
||||
static bool StartJavaHandlerAtCrash(
|
||||
const std::string& class_name,
|
||||
const std::vector<std::string>* env,
|
||||
const base::FilePath& database,
|
||||
const base::FilePath& metrics_dir,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
const std::vector<std::string>& arguments);
|
||||
|
||||
//! \brief Executes `/system/bin/app_process` and loads a Java class.
|
||||
//!
|
||||
//! \param[in] class_name The fully qualified class name to load, which must
|
||||
//! define a `main()` method to be invoked by `app_process`. Arguments
|
||||
//! will be passed to this method as though it were the Crashpad handler.
|
||||
//! This class is expected to load a native library defining
|
||||
//! crashpad::HandlerMain() and pass the arguments to it.
|
||||
//! \param[in] env A vector of environment variables of the form `var=value`
|
||||
//! defining the environment in which to execute `app_process`. If this
|
||||
//! value is `nullptr`, the application's current environment will be
|
||||
//! used.
|
||||
//! \param[in] database The path to a Crashpad database. The handler will be
|
||||
//! started with this path as its `--database` argument.
|
||||
//! \param[in] metrics_dir The path to an already existing directory where
|
||||
//! metrics files can be stored. The handler will be started with this
|
||||
//! path as its `--metrics-dir` argument.
|
||||
//! \param[in] url The URL of an upload server. The handler will be started
|
||||
//! with this URL as its `--url` argument.
|
||||
//! \param[in] annotations Process annotations to set in each crash report.
|
||||
//! The handler will be started with an `--annotation` argument for each
|
||||
//! element in this map.
|
||||
//! \param[in] arguments Additional arguments to pass to the Crashpad handler.
|
||||
//! Arguments passed in other parameters and arguments required to perform
|
||||
//! the handshake are the responsibility of this method, and must not be
|
||||
//! specified in this parameter.
|
||||
//! \param[in] socket The server end of a socket pair. The client end should
|
||||
//! be used with an ExceptionHandlerClient.
|
||||
//!
|
||||
//! \return `true` on success, `false` on failure with a message logged.
|
||||
static bool StartJavaHandlerForClient(
|
||||
const std::string& class_name,
|
||||
const std::vector<std::string>* env,
|
||||
const base::FilePath& database,
|
||||
const base::FilePath& metrics_dir,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
const std::vector<std::string>& arguments,
|
||||
int socket);
|
||||
#endif // OS_ANDROID || DOXYGEN
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_ANDROID) || DOXYGEN
|
||||
//! \brief Installs a signal handler to launch a handler process in reponse to
|
||||
//! a crash.
|
||||
|
@ -62,7 +62,7 @@ bool CrashpadClient::StartHandler(
|
||||
handler, database, metrics_dir, url, annotations, arguments);
|
||||
|
||||
std::vector<const char*> argv;
|
||||
ConvertArgvStrings(argv_strings, &argv);
|
||||
StringVectorToCStringVector(argv_strings, &argv);
|
||||
|
||||
// Follow the same protocol as devmgr and crashlogger in Zircon (that is,
|
||||
// process handle as handle 0, with type USER0, exception port handle as
|
||||
|
@ -45,6 +45,39 @@ std::string FormatArgumentAddress(const std::string& name, void* addr) {
|
||||
return base::StringPrintf("--%s=%p", name.c_str(), addr);
|
||||
}
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
|
||||
std::vector<std::string> BuildAppProcessArgs(
|
||||
const std::string& class_name,
|
||||
const base::FilePath& database,
|
||||
const base::FilePath& metrics_dir,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
const std::vector<std::string>& arguments,
|
||||
int socket) {
|
||||
std::vector<std::string> argv;
|
||||
#if defined(ARCH_CPU_64_BIT)
|
||||
argv.push_back("/system/bin/app_process64");
|
||||
#else
|
||||
argv.push_back("/system/bin/app_process32");
|
||||
#endif
|
||||
argv.push_back("/system/bin");
|
||||
argv.push_back("--application");
|
||||
argv.push_back(class_name);
|
||||
|
||||
std::vector<std::string> handler_argv = BuildHandlerArgvStrings(
|
||||
base::FilePath(), database, metrics_dir, url, annotations, arguments);
|
||||
|
||||
if (socket != kInvalidFileHandle) {
|
||||
handler_argv.push_back(FormatArgumentInt("initial-client-fd", socket));
|
||||
}
|
||||
|
||||
argv.insert(argv.end(), handler_argv.begin() + 1, handler_argv.end());
|
||||
return argv;
|
||||
}
|
||||
|
||||
#endif // OS_ANDROID
|
||||
|
||||
class SignalHandler {
|
||||
public:
|
||||
virtual void HandleCrashFatal(int signo,
|
||||
@ -73,13 +106,20 @@ class LaunchAtCrashHandler : public SignalHandler {
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool Initialize(std::vector<std::string>* argv_in) {
|
||||
bool Initialize(std::vector<std::string>* argv_in,
|
||||
const std::vector<std::string>* envp) {
|
||||
argv_strings_.swap(*argv_in);
|
||||
|
||||
if (envp) {
|
||||
envp_strings_ = *envp;
|
||||
StringVectorToCStringVector(envp_strings_, &envp_);
|
||||
set_envp_ = true;
|
||||
}
|
||||
|
||||
argv_strings_.push_back(FormatArgumentAddress("trace-parent-with-exception",
|
||||
&exception_information_));
|
||||
|
||||
ConvertArgvStrings(argv_strings_, &argv_);
|
||||
StringVectorToCStringVector(argv_strings_, &argv_);
|
||||
return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr);
|
||||
}
|
||||
|
||||
@ -107,7 +147,13 @@ class LaunchAtCrashHandler : public SignalHandler {
|
||||
return false;
|
||||
}
|
||||
if (pid == 0) {
|
||||
execv(argv_[0], const_cast<char* const*>(argv_.data()));
|
||||
if (set_envp_) {
|
||||
execve(argv_[0],
|
||||
const_cast<char* const*>(argv_.data()),
|
||||
const_cast<char* const*>(envp_.data()));
|
||||
} else {
|
||||
execv(argv_[0], const_cast<char* const*>(argv_.data()));
|
||||
}
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -135,6 +181,9 @@ class LaunchAtCrashHandler : public SignalHandler {
|
||||
|
||||
std::vector<std::string> argv_strings_;
|
||||
std::vector<const char*> argv_;
|
||||
std::vector<std::string> envp_strings_;
|
||||
std::vector<const char*> envp_;
|
||||
bool set_envp_ = false;
|
||||
ExceptionInformation exception_information_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LaunchAtCrashHandler);
|
||||
@ -167,6 +216,51 @@ bool CrashpadClient::StartHandler(
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
|
||||
// static
|
||||
bool CrashpadClient::StartJavaHandlerAtCrash(
|
||||
const std::string& class_name,
|
||||
const std::vector<std::string>* env,
|
||||
const base::FilePath& database,
|
||||
const base::FilePath& metrics_dir,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
const std::vector<std::string>& arguments) {
|
||||
std::vector<std::string> argv = BuildAppProcessArgs(class_name,
|
||||
database,
|
||||
metrics_dir,
|
||||
url,
|
||||
annotations,
|
||||
arguments,
|
||||
kInvalidFileHandle);
|
||||
|
||||
auto signal_handler = LaunchAtCrashHandler::Get();
|
||||
if (signal_handler->Initialize(&argv, env)) {
|
||||
DCHECK(!g_crash_handler);
|
||||
g_crash_handler = signal_handler;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CrashpadClient::StartJavaHandlerForClient(
|
||||
const std::string& class_name,
|
||||
const std::vector<std::string>* env,
|
||||
const base::FilePath& database,
|
||||
const base::FilePath& metrics_dir,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
const std::vector<std::string>& arguments,
|
||||
int socket) {
|
||||
std::vector<std::string> argv = BuildAppProcessArgs(
|
||||
class_name, database, metrics_dir, url, annotations, arguments, socket);
|
||||
return DoubleForkAndExec(argv, env, socket, false, nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// static
|
||||
bool CrashpadClient::StartHandlerAtCrash(
|
||||
const base::FilePath& handler,
|
||||
@ -179,7 +273,7 @@ bool CrashpadClient::StartHandlerAtCrash(
|
||||
handler, database, metrics_dir, url, annotations, arguments);
|
||||
|
||||
auto signal_handler = LaunchAtCrashHandler::Get();
|
||||
if (signal_handler->Initialize(&argv)) {
|
||||
if (signal_handler->Initialize(&argv, nullptr)) {
|
||||
DCHECK(!g_crash_handler);
|
||||
g_crash_handler = signal_handler;
|
||||
return true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user