mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-28 15:50:26 +08:00
android: Add methods to start handler with /system/bin/linker
Starting with Android Q, Bionic's linker will support loading executables from an APK, replacing the /system/bin/app_process workaround. libhandler_trampoline.so is a small executable, which `dlopen()`s the handler code from another native library allowing de-duplicating shared code with that library without having that library available for a more direct link time dependency. Bug: 928422 Change-Id: Ib126b8fca6005a34b9e4ef103eb1383dc0c554ea Reviewed-on: https://chromium-review.googlesource.com/c/1477336 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
dc17650336
commit
99bf283e54
@ -188,6 +188,97 @@ class CrashpadClient {
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
const std::vector<std::string>& arguments,
|
||||
int socket);
|
||||
|
||||
//! \brief Installs a signal handler to start a Crashpad handler process by
|
||||
//! loading it with `/system/bin/linker`.
|
||||
//!
|
||||
//! This method is only supported by Android Q+.
|
||||
//!
|
||||
//! \param[in] handler_trampoline The path to a Crashpad handler trampoline
|
||||
//! executable, possibly located within an apk, e.g.
|
||||
//! "/data/app/myapk.apk!/myabi/libcrashpad_handler_trampoline.so".
|
||||
//! \param[in] handler_library The name of a library exporting the symbol
|
||||
//! `CrashpadHandlerMain()`. The path to this library must be present in
|
||||
//! `LD_LIBRARY_PATH`.
|
||||
//! \param[in] is_64_bit `true` if \a handler_trampoline and \a
|
||||
//! handler_library are 64-bit objects. They must have the same bitness.
|
||||
//! \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 StartHandlerWithLinkerAtCrash(
|
||||
const std::string& handler_trampoline,
|
||||
const std::string& handler_library,
|
||||
bool is_64_bit,
|
||||
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 Starts a Crashpad handler process with an initial client by loading
|
||||
//! it with `/system/bin/linker`.
|
||||
//!
|
||||
//! This method is only supported by Android Q+.
|
||||
//!
|
||||
//! \param[in] handler_trampoline The path to a Crashpad handler trampoline
|
||||
//! executable, possibly located within an apk, e.g.
|
||||
//! "/data/app/myapk.apk!/myabi/libcrashpad_handler_trampoline.so".
|
||||
//! \param[in] handler_library The name of a library exporting the symbol
|
||||
//! `CrashpadHandlerMain()`. The path to this library must be present in
|
||||
//! `LD_LIBRARY_PATH`.
|
||||
//! \param[in] is_64_bit `true` if \a handler_trampoline and \a
|
||||
//! handler_library are 64-bit objects. They must have the same bitness.
|
||||
//! \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 StartHandlerWithLinkerForClient(
|
||||
const std::string& handler_trampoline,
|
||||
const std::string& handler_library,
|
||||
bool is_64_bit,
|
||||
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
|
||||
|
@ -77,6 +77,36 @@ std::vector<std::string> BuildAppProcessArgs(
|
||||
return argv;
|
||||
}
|
||||
|
||||
std::vector<std::string> BuildArgsToLaunchWithLinker(
|
||||
const std::string& handler_trampoline,
|
||||
const std::string& handler_library,
|
||||
bool is_64_bit,
|
||||
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 (is_64_bit) {
|
||||
argv.push_back("/system/bin/linker64");
|
||||
} else {
|
||||
argv.push_back("/system/bin/linker");
|
||||
}
|
||||
argv.push_back(handler_trampoline);
|
||||
argv.push_back(handler_library);
|
||||
|
||||
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
|
||||
|
||||
// Launches a single use handler to snapshot this process.
|
||||
@ -251,6 +281,61 @@ bool CrashpadClient::StartJavaHandlerForClient(
|
||||
return DoubleForkAndExec(argv, env, socket, false, nullptr);
|
||||
}
|
||||
|
||||
// static
|
||||
bool CrashpadClient::StartHandlerWithLinkerAtCrash(
|
||||
const std::string& handler_trampoline,
|
||||
const std::string& handler_library,
|
||||
bool is_64_bit,
|
||||
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 =
|
||||
BuildArgsToLaunchWithLinker(handler_trampoline,
|
||||
handler_library,
|
||||
is_64_bit,
|
||||
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::StartHandlerWithLinkerForClient(
|
||||
const std::string& handler_trampoline,
|
||||
const std::string& handler_library,
|
||||
bool is_64_bit,
|
||||
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 =
|
||||
BuildArgsToLaunchWithLinker(handler_trampoline,
|
||||
handler_library,
|
||||
is_64_bit,
|
||||
database,
|
||||
metrics_dir,
|
||||
url,
|
||||
annotations,
|
||||
arguments,
|
||||
socket);
|
||||
return DoubleForkAndExec(argv, env, socket, false, nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// static
|
||||
|
@ -166,6 +166,21 @@ if (crashpad_is_android) {
|
||||
"$root_out_dir/libcrashpad_handler.so",
|
||||
]
|
||||
}
|
||||
|
||||
crashpad_executable("crashpad_handler_trampoline") {
|
||||
set_sources_assignment_filter([])
|
||||
output_name = "libcrashpad_handler_trampoline.so"
|
||||
|
||||
sources = [
|
||||
"linux/handler_trampoline.cc",
|
||||
]
|
||||
|
||||
ldflags = [ "-llog" ]
|
||||
|
||||
if (crashpad_is_in_chromium) {
|
||||
no_default_deps = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crashpad_executable("crashpad_handler_test_extended_handler") {
|
||||
|
@ -497,6 +497,18 @@ class ScopedStoppable {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
|
||||
extern "C" {
|
||||
__attribute__((visibility("default"), used)) int CrashpadHandlerMain(
|
||||
int argc,
|
||||
char* argv[]) {
|
||||
return HandlerMain(argc, argv, nullptr);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
#endif // OS_ANDROID
|
||||
|
||||
int HandlerMain(int argc,
|
||||
char* argv[],
|
||||
const UserStreamDataSources* user_stream_sources) {
|
||||
|
45
handler/linux/handler_trampoline.cc
Normal file
45
handler/linux/handler_trampoline.cc
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2019 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <android/log.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// The first argument passed to the trampoline is the name of the native library
|
||||
// exporting the symbol `CrashpadHandlerMain`. The remaining arguments are the
|
||||
// same as for `HandlerMain()`.
|
||||
int main(int argc, char* argv[]) {
|
||||
static constexpr char kTag[] = "crashpad";
|
||||
|
||||
if (argc < 2) {
|
||||
__android_log_print(ANDROID_LOG_FATAL, kTag, "usage: %s <path>", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL);
|
||||
if (!handle) {
|
||||
__android_log_print(ANDROID_LOG_FATAL, kTag, "dlopen: %s", dlerror());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
using MainType = int (*)(int, char*[]);
|
||||
MainType crashpad_main =
|
||||
reinterpret_cast<MainType>(dlsym(handle, "CrashpadHandlerMain"));
|
||||
if (!crashpad_main) {
|
||||
__android_log_print(ANDROID_LOG_FATAL, kTag, "dlsym: %s", dlerror());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return crashpad_main(argc - 1, argv + 1);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user