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) {
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) {
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 {
uncompress_shared_libraries = true
@ -42,6 +52,11 @@ template("system_webview_apk_tmpl") {
# architecture.
if (android_64bit_target_cpu) {
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) {
secondary_native_lib_placeholders = [ "libdummy.so" ]
}

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

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

@ -57,13 +57,29 @@ public class BuildInfo {
BuildInfo buildInfo = getInstance();
String hostPackageName = ContextUtils.getApplicationContext().getPackageName();
return new String[] {
Build.BRAND, Build.DEVICE, Build.ID, Build.MANUFACTURER, Build.MODEL,
String.valueOf(Build.VERSION.SDK_INT), 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,
Build.BRAND,
Build.DEVICE,
Build.ID,
Build.MANUFACTURER,
Build.MODEL,
String.valueOf(Build.VERSION.SDK_INT),
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'
and 'android_linker' 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
# Add prefix to prevent android install from extracting upon install.
if has_crazy_linker:

@ -42,7 +42,9 @@ def main():
options = parser.parse_args()
# 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:
symbol_list.append('Java_*')

@ -348,6 +348,30 @@ template("monochrome_public_common_apk_or_module_tmpl") {
if (!defined(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 += [
"//chrome/android:chrome_public_non_pak_assets",
"//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.
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) {
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 {
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)) {
# Define expectations only for target_cpu covered by trybots.
if (target_cpu == "arm") {
expected_static_initializer_count = 4
expected_static_initializer_count = 6
} 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) {
secondary_abi_shared_libraries =
[ "//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 {
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) {

@ -66,7 +66,10 @@ static_library("app") {
}
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) {

@ -4,6 +4,7 @@
#include "components/crash/content/app/crashpad.h"
#include <dlfcn.h>
#include <string.h>
#include <sys/socket.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__)
#define CURRENT_ABI "armeabi-v7a"
#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
// 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());
std::string classpath;
@ -299,6 +328,12 @@ bool BuildEnvironmentWithApk(std::vector<std::string>* result) {
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) {
@ -414,6 +449,19 @@ bool SetLdLibraryPath(const base::FilePath& lib_path) {
}
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:
static HandlerStarter* Get() {
static HandlerStarter* instance = new HandlerStarter();
@ -443,25 +491,35 @@ class HandlerStarter {
#if defined(OS_ANDROID)
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) {
return database_path;
}
if (use_java_handler_) {
if (use_java_handler_ || !handler_trampoline_.empty()) {
std::vector<std::string> env;
if (!BuildEnvironmentWithApk(&env)) {
if (!BuildEnvironmentWithApk(kUse64Bit, &env)) {
return database_path;
}
// TODO(jperaza): The logic for constructing an appropriate
// CLASSPATH/LD_LIBRARY_PATH won't work for Android Q+. The handler will
// need to be launched by executing the dynamic linker instead.
bool result = GetCrashpadClient().StartJavaHandlerAtCrash(
kCrashpadJavaMain, &env, database_path, metrics_path, url,
process_annotations, arguments);
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;
}
@ -501,18 +559,21 @@ class HandlerStarter {
}
#if defined(OS_ANDROID)
if (use_java_handler_) {
if (use_java_handler_ || !handler_trampoline_.empty()) {
std::vector<std::string> env;
if (!BuildEnvironmentWithApk(&env)) {
if (!BuildEnvironmentWithApk(kUse64Bit, &env)) {
return false;
}
// TODO(jperaza): The logic for constructing an appropriate
// CLASSPATH/LD_LIBRARY_PATH won't work for Android Q+. The handler will
// need to be launched by executing the dynamic linker instead.
bool result = GetCrashpadClient().StartJavaHandlerForClient(
kCrashpadJavaMain, &env, database_path, metrics_path, url,
process_annotations, arguments, fd);
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;
}
#endif
@ -532,6 +593,8 @@ class HandlerStarter {
crashpad::SanitizationInformation browser_sanitization_info_;
#if defined(OS_ANDROID)
std::string handler_trampoline_;
std::string handler_library_;
bool use_java_handler_ = false;
#endif