0

android: Launch Crashpad with /system/bin/linker on Q

This adds a small executable, libcrashpad_handler_trampoline.so, to
Monochrome, Trichrome, and SystemWebView. The trampoline loads the
remaining Crashpad handler code from the main native library, which
must export `CrashpadHandlerMain()`.

All three packages will continue to use /system/bin/app_process to
launch Crashpad on P-.

Note on static_initializers.gni:

There aren't any real, new static initializers. The increased count is
due to the addition of the new object. Static initializers are counted
by measuring the size of each object's .init_array and dividing by the
object's pointer size. libcrashpad_handler_trampoline.so has two
invalid slots which are ignored by the loader:

readelf -x .init_array libcrashpad_handler_trampoline.so

Hex dump of section '.init_array':
  0x00001008 ffffffff 00000000

Bug: 928422
Change-Id: Iba56cd6feda73ebc91f6758724d823e48b5c6e8f
Reviewed-on: https://chromium-review.googlesource.com/c/1454078
Reviewed-by: Richard Coles <torne@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Cr-Commit-Position: refs/heads/master@{#635269}
This commit is contained in:
Joshua Peraza
2019-02-25 21:49:11 +00:00
committed by Commit Bot
parent 7e453e2b3e
commit 54c5c662fc
11 changed files with 171 additions and 34 deletions

@ -32,8 +32,18 @@ template("system_webview_apk_tmpl") {
if (!_use_trichrome_library) { if (!_use_trichrome_library) {
shared_libraries = [ "//android_webview:libwebviewchromium" ] shared_libraries = [ "//android_webview:libwebviewchromium" ]
deps += [
"//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline",
]
loadable_modules = [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
if (build_apk_secondary_abi && android_64bit_target_cpu) { if (build_apk_secondary_abi && android_64bit_target_cpu) {
secondary_abi_shared_libraries = [ "//android_webview:libwebviewchromium($android_secondary_abi_toolchain)" ] secondary_abi_shared_libraries = [ "//android_webview:libwebviewchromium($android_secondary_abi_toolchain)" ]
_trampoline = "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline($android_secondary_abi_toolchain)"
deps += [ _trampoline ]
_secondary_out_dir = get_label_info(_trampoline, "root_out_dir")
secondary_abi_loadable_modules =
[ "$_secondary_out_dir/libcrashpad_handler_trampoline.so" ]
} }
} else { } else {
uncompress_shared_libraries = true uncompress_shared_libraries = true
@ -42,6 +52,11 @@ template("system_webview_apk_tmpl") {
# architecture. # architecture.
if (android_64bit_target_cpu) { if (android_64bit_target_cpu) {
shared_libraries = [ "//android_webview:monochrome" ] shared_libraries = [ "//android_webview:monochrome" ]
deps += [
"//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline",
]
loadable_modules = [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
if (build_apk_secondary_abi) { if (build_apk_secondary_abi) {
secondary_native_lib_placeholders = [ "libdummy.so" ] secondary_native_lib_placeholders = [ "libdummy.so" ]
} }

@ -75,7 +75,8 @@ BuildInfo::BuildInfo(const std::vector<std::string>& params)
firebase_app_id_(StrDupParam(params, 18)), firebase_app_id_(StrDupParam(params, 18)),
custom_themes_(StrDupParam(params, 19)), custom_themes_(StrDupParam(params, 19)),
resources_version_(StrDupParam(params, 20)), resources_version_(StrDupParam(params, 20)),
extracted_file_suffix_(params[21]) {} extracted_file_suffix_(params[21]),
is_at_least_q_(GetIntParam(params, 22)) {}
// static // static
BuildInfo* BuildInfo::GetInstance() { BuildInfo* BuildInfo::GetInstance() {

@ -122,6 +122,8 @@ class BASE_EXPORT BuildInfo {
return sdk_int_; return sdk_int_;
} }
bool is_at_least_q() const { return is_at_least_q_; }
private: private:
friend struct BuildInfoSingletonTraits; friend struct BuildInfoSingletonTraits;
@ -154,6 +156,7 @@ class BASE_EXPORT BuildInfo {
const char* const resources_version_; const char* const resources_version_;
// Not needed by breakpad. // Not needed by breakpad.
const std::string extracted_file_suffix_; const std::string extracted_file_suffix_;
const bool is_at_least_q_;
DISALLOW_COPY_AND_ASSIGN(BuildInfo); DISALLOW_COPY_AND_ASSIGN(BuildInfo);
}; };

@ -57,13 +57,29 @@ public class BuildInfo {
BuildInfo buildInfo = getInstance(); BuildInfo buildInfo = getInstance();
String hostPackageName = ContextUtils.getApplicationContext().getPackageName(); String hostPackageName = ContextUtils.getApplicationContext().getPackageName();
return new String[] { return new String[] {
Build.BRAND, Build.DEVICE, Build.ID, Build.MANUFACTURER, Build.MODEL, Build.BRAND,
String.valueOf(Build.VERSION.SDK_INT), Build.TYPE, Build.BOARD, hostPackageName, Build.DEVICE,
String.valueOf(buildInfo.hostVersionCode), buildInfo.hostPackageLabel, Build.ID,
buildInfo.packageName, String.valueOf(buildInfo.versionCode), buildInfo.versionName, Build.MANUFACTURER,
buildInfo.androidBuildFingerprint, buildInfo.gmsVersionCode, Build.MODEL,
buildInfo.installerPackageName, buildInfo.abiString, BuildConfig.FIREBASE_APP_ID, String.valueOf(Build.VERSION.SDK_INT),
buildInfo.customThemes, buildInfo.resourcesVersion, buildInfo.extractedFileSuffix, Build.TYPE,
Build.BOARD,
hostPackageName,
String.valueOf(buildInfo.hostVersionCode),
buildInfo.hostPackageLabel,
buildInfo.packageName,
String.valueOf(buildInfo.versionCode),
buildInfo.versionName,
buildInfo.androidBuildFingerprint,
buildInfo.gmsVersionCode,
buildInfo.installerPackageName,
buildInfo.abiString,
BuildConfig.FIREBASE_APP_ID,
buildInfo.customThemes,
buildInfo.resourcesVersion,
buildInfo.extractedFileSuffix,
isAtLeastQ() ? "1" : "0",
}; };
} }

@ -208,7 +208,7 @@ def _AddNativeLibraries(out_apk, native_libs, android_abi, uncompress):
if (uncompress and os.path.splitext(basename)[1] == '.so' if (uncompress and os.path.splitext(basename)[1] == '.so'
and 'android_linker' not in basename and 'android_linker' not in basename
and (not has_crazy_linker or 'clang_rt' not in basename) and (not has_crazy_linker or 'clang_rt' not in basename)
and 'crashpad_handler' not in basename): and (not has_crazy_linker or 'crashpad_handler' not in basename)):
compress = False compress = False
# Add prefix to prevent android install from extracting upon install. # Add prefix to prevent android install from extracting upon install.
if has_crazy_linker: if has_crazy_linker:

@ -42,7 +42,9 @@ def main():
options = parser.parse_args() options = parser.parse_args()
# JNI_OnLoad is always exported. # JNI_OnLoad is always exported.
symbol_list = ['JNI_OnLoad'] # CrashpadHandlerMain() is the entry point to the Crashpad handler, required
# for libcrashpad_handler_trampoline.so.
symbol_list = ['CrashpadHandlerMain', 'JNI_OnLoad']
if options.export_java_symbols: if options.export_java_symbols:
symbol_list.append('Java_*') symbol_list.append('Java_*')

@ -348,6 +348,30 @@ template("monochrome_public_common_apk_or_module_tmpl") {
if (!defined(deps)) { if (!defined(deps)) {
deps = [] deps = []
} }
if (!defined(loadable_modules)) {
loadable_modules = []
}
if (!defined(secondary_abi_loadable_modules)) {
secondary_abi_loadable_modules = []
}
if (!is_trichrome) {
deps += [
"//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline",
]
loadable_modules += [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
if (android_64bit_target_cpu && build_apk_secondary_abi &&
(!defined(invoker.is_64_bit_browser) || !invoker.is_64_bit_browser ||
invoker.include_32_bit_webview)) {
_trampoline = "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline($android_secondary_abi_toolchain)"
deps += [ _trampoline ]
_secondary_out_dir = get_label_info(_trampoline, "root_out_dir")
secondary_abi_loadable_modules +=
[ "$_secondary_out_dir/libcrashpad_handler_trampoline.so" ]
}
}
deps += [ deps += [
"//chrome/android:chrome_public_non_pak_assets", "//chrome/android:chrome_public_non_pak_assets",
"//components/crash/android:handler_java", "//components/crash/android:handler_java",
@ -403,11 +427,11 @@ template("monochrome_public_common_apk_or_module_tmpl") {
# We store this as a separate .so in the APK and only load as needed. # We store this as a separate .so in the APK and only load as needed.
if (android_64bit_target_cpu && build_apk_secondary_abi) { if (android_64bit_target_cpu && build_apk_secondary_abi) {
secondary_abi_loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ] secondary_abi_loadable_modules += [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
} else if (android_64bit_target_cpu && !build_apk_secondary_abi) { } else if (android_64bit_target_cpu && !build_apk_secondary_abi) {
loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ] loadable_modules += [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
} else { } else {
loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ] loadable_modules += [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
} }
} }
} }

@ -13,8 +13,8 @@ if (current_toolchain == default_toolchain &&
(!is_debug && !using_sanitizer && proprietary_codecs)) { (!is_debug && !using_sanitizer && proprietary_codecs)) {
# Define expectations only for target_cpu covered by trybots. # Define expectations only for target_cpu covered by trybots.
if (target_cpu == "arm") { if (target_cpu == "arm") {
expected_static_initializer_count = 4 expected_static_initializer_count = 6
} else if (target_cpu == "arm64") { } else if (target_cpu == "arm64") {
expected_static_initializer_count = 3 expected_static_initializer_count = 5
} }
} }

@ -82,9 +82,19 @@ template("trichrome_library_apk_tmpl") {
if (build_apk_secondary_abi) { if (build_apk_secondary_abi) {
secondary_abi_shared_libraries = secondary_abi_shared_libraries =
[ "//chrome/android:monochrome_secondary_abi_lib" ] [ "//chrome/android:monochrome_secondary_abi_lib" ]
_trampoline = "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline($android_secondary_abi_toolchain)"
deps += [ _trampoline ]
_secondary_out_dir = get_label_info(_trampoline, "root_out_dir")
secondary_abi_loadable_modules =
[ "$_secondary_out_dir/libcrashpad_handler_trampoline.so" ]
} }
} else { } else {
shared_libraries = [ "//chrome/android:monochrome" ] shared_libraries = [ "//chrome/android:monochrome" ]
deps += [
"//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline",
]
loadable_modules = [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
} }
if (!is_java_debug) { if (!is_java_debug) {

@ -66,7 +66,10 @@ static_library("app") {
} }
if (is_android) { if (is_android) {
deps += [ "//components/crash/android:jni_headers" ] deps += [
"//components/crash/android:jni_headers",
"//third_party/crashpad/crashpad/handler",
]
} }
if (is_android || is_linux) { if (is_android || is_linux) {

@ -4,6 +4,7 @@
#include "components/crash/content/app/crashpad.h" #include "components/crash/content/app/crashpad.h"
#include <dlfcn.h>
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h> #include <sys/types.h>
@ -246,6 +247,33 @@ void SetBuildInfoAnnotations(std::map<std::string, std::string>* annotations) {
} }
} }
// 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) {
Dl_info info;
if (dladdr(reinterpret_cast<void*>(&GetHandlerTrampoline), &info) == 0) {
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__) #if defined(__arm__) && defined(__ARM_ARCH_7A__)
#define CURRENT_ABI "armeabi-v7a" #define CURRENT_ABI "armeabi-v7a"
#elif defined(__arm__) #elif defined(__arm__)
@ -281,7 +309,8 @@ void MakePackagePaths(std::string* classpath, std::string* libpath) {
// Copies and extends the current environment with CLASSPATH and LD_LIBRARY_PATH // Copies and extends the current environment with CLASSPATH and LD_LIBRARY_PATH
// set to library paths in the APK. // set to library paths in the APK.
bool BuildEnvironmentWithApk(std::vector<std::string>* result) { bool BuildEnvironmentWithApk(bool use_64_bit,
std::vector<std::string>* result) {
DCHECK(result->empty()); DCHECK(result->empty());
std::string classpath; std::string classpath;
@ -299,6 +328,12 @@ bool BuildEnvironmentWithApk(std::vector<std::string>* result) {
env->GetVar(kLdLibraryPathVar, &current_library_path); env->GetVar(kLdLibraryPathVar, &current_library_path);
library_path += ":" + 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("CLASSPATH=" + classpath);
result->push_back("LD_LIBRARY_PATH=" + library_path); result->push_back("LD_LIBRARY_PATH=" + library_path);
for (char** envp = environ; *envp != nullptr; ++envp) { for (char** envp = environ; *envp != nullptr; ++envp) {
@ -414,6 +449,19 @@ bool SetLdLibraryPath(const base::FilePath& lib_path) {
} }
class HandlerStarter { class HandlerStarter {
#if defined(OS_ANDROID)
// 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
#endif // OS_ANDROID
public: public:
static HandlerStarter* Get() { static HandlerStarter* Get() {
static HandlerStarter* instance = new HandlerStarter(); static HandlerStarter* instance = new HandlerStarter();
@ -443,25 +491,35 @@ class HandlerStarter {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
if (!base::PathExists(handler_path)) { if (!base::PathExists(handler_path)) {
use_java_handler_ = true; // The linker doesn't support loading executables passed on its command
// line until Q.
if (base::android::BuildInfo::GetInstance()->is_at_least_q()) {
bool found_library =
GetHandlerTrampoline(&handler_trampoline_, &handler_library_);
DCHECK(found_library);
} else {
use_java_handler_ = true;
}
} }
if (!dump_at_crash) { if (!dump_at_crash) {
return database_path; return database_path;
} }
if (use_java_handler_) { if (use_java_handler_ || !handler_trampoline_.empty()) {
std::vector<std::string> env; std::vector<std::string> env;
if (!BuildEnvironmentWithApk(&env)) { if (!BuildEnvironmentWithApk(kUse64Bit, &env)) {
return database_path; return database_path;
} }
// TODO(jperaza): The logic for constructing an appropriate bool result = use_java_handler_
// CLASSPATH/LD_LIBRARY_PATH won't work for Android Q+. The handler will ? GetCrashpadClient().StartJavaHandlerAtCrash(
// need to be launched by executing the dynamic linker instead. kCrashpadJavaMain, &env, database_path,
bool result = GetCrashpadClient().StartJavaHandlerAtCrash( metrics_path, url, process_annotations, arguments)
kCrashpadJavaMain, &env, database_path, metrics_path, url, : GetCrashpadClient().StartHandlerWithLinkerAtCrash(
process_annotations, arguments); handler_trampoline_, handler_library_, kUse64Bit,
&env, database_path, metrics_path, url,
process_annotations, arguments);
DCHECK(result); DCHECK(result);
return database_path; return database_path;
} }
@ -501,18 +559,21 @@ class HandlerStarter {
} }
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
if (use_java_handler_) { if (use_java_handler_ || !handler_trampoline_.empty()) {
std::vector<std::string> env; std::vector<std::string> env;
if (!BuildEnvironmentWithApk(&env)) { if (!BuildEnvironmentWithApk(kUse64Bit, &env)) {
return false; return false;
} }
// TODO(jperaza): The logic for constructing an appropriate bool result =
// CLASSPATH/LD_LIBRARY_PATH won't work for Android Q+. The handler will use_java_handler_
// need to be launched by executing the dynamic linker instead. ? GetCrashpadClient().StartJavaHandlerForClient(
bool result = GetCrashpadClient().StartJavaHandlerForClient( kCrashpadJavaMain, &env, database_path, metrics_path, url,
kCrashpadJavaMain, &env, database_path, metrics_path, url, process_annotations, arguments, fd)
process_annotations, arguments, fd); : GetCrashpadClient().StartHandlerWithLinkerForClient(
handler_trampoline_, handler_library_, kUse64Bit, &env,
database_path, metrics_path, url, process_annotations,
arguments, fd);
return result; return result;
} }
#endif #endif
@ -532,6 +593,8 @@ class HandlerStarter {
crashpad::SanitizationInformation browser_sanitization_info_; crashpad::SanitizationInformation browser_sanitization_info_;
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
std::string handler_trampoline_;
std::string handler_library_;
bool use_java_handler_ = false; bool use_java_handler_ = false;
#endif #endif