Commit dbca191e authored by Joshua Peraza's avatar Joshua Peraza Committed by Commit Bot

Package Crashpad's handler into various APKs

For Chromecast, Content Shell, and non-monochrome Clank/Webview:

The Crashpad handler is a standalone executable, packaged like a
loadable module and named libcrashpad_handler.so in order to not be
ignored by Android's APK installer.

For Monochrome:

The Crashpad handler is linked into libmonochrome.so. At crash-time
/system/bin/app_process{32,64} is exec-ed, running CrashpadMain.java
which loads libmonochrome.so and runs the native HandlerMain().

This strategy is not used for non-monochrome APKs (i.e. pre-N) because
on L, Android's loader is not yet capable of loading native libraries
from the APK. This is normally performed by the Chromium linker which
can't be used by CrashpadMain.java because /system/bin/app_process
doesn't initialize the process like a normal Android application
(specifically, no ContextImpl has been created, so any calls to e.g.
appContext.getApplicationInfo() will segfault).

Binary-Size: MonochromePublic.apk increases in size by 100 KB.
ChromeModernPublic.apk increases in size by 203KB (587 KB
increase in install size because libcrashpad_handler.so is extracted
from the APK). Possible mitigations for this increase are TODO:

For J, K: We could link the handler directly into libchrome.so and let
that be our handler executable. This would de-dup portions of libbase
that are currently linked into both libchrome.so and
libcrashpad_handler.so.

For L, M: It might be possible to get the chromium linker (or Bionic's
linker on M) to dlopen libchrome.so from the APK for a trampoline
libcrashpad_handler.so to de-dup libbase.

Bug: crashpad:30
Change-Id: If5b3752f26455e5c7aef3278b4bd2076ef1b7b65
Reviewed-on: https://chromium-review.googlesource.com/1150774Reviewed-by: default avatarBo <boliu@chromium.org>
Reviewed-by: default avataragrieve <agrieve@chromium.org>
Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Reviewed-by: default avatarRichard Coles <torne@chromium.org>
Reviewed-by: default avatarLuke Halliwell <halliwell@chromium.org>
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Cr-Commit-Position: refs/heads/master@{#594853}
parent 0ba729b1
......@@ -418,6 +418,7 @@ if (android_64bit_target_cpu) {
shared_library("monochrome") {
deps = [
":webview_entry_point",
"//components/crash/android:crashpad_main",
]
configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
configs += [ "//build/config/android:hide_all_but_jni" ]
......
......@@ -18,8 +18,11 @@ template("system_webview_apk_tmpl") {
"//android_webview/glue",
"//android_webview/support_library:support_lib_glue_java",
"//base:base_java",
"//third_party/crashpad/crashpad/handler:crashpad_handler_named_as_so",
]
loadable_modules = [ "$root_out_dir/libcrashpad_handler.so" ]
if (!defined(alternative_android_sdk_dep)) {
alternative_android_sdk_dep = webview_framework_dep
}
......@@ -32,6 +35,12 @@ template("system_webview_apk_tmpl") {
native_lib_version_arg = "@FileArg($_native_lib_file:full-quoted)"
if (build_apk_secondary_abi && android_64bit_target_cpu) {
secondary_abi_shared_libraries = [ "//android_webview:libwebviewchromium($android_secondary_abi_toolchain)" ]
deps += [ "//third_party/crashpad/crashpad/handler:crashpad_handler_named_as_so($android_secondary_abi_toolchain)" ]
toolchain_out_dir = get_label_info(
"//third_party/crashpad/crashpad/handler:crashpad_handler_named_as_so($android_secondary_abi_toolchain)",
"root_out_dir")
secondary_abi_loadable_modules =
[ "${toolchain_out_dir}/libcrashpad_handler.so" ]
}
aapt_locale_whitelist = locales
......
......@@ -49,6 +49,7 @@ android_apk("webview_instrumentation_apk") {
"//components/policy/android:policy_java_test_support",
"//content/public/android:content_java",
"//third_party/android_support_test_runner:runner_java",
"//third_party/crashpad/crashpad/handler:crashpad_handler_named_as_so",
"//third_party/junit",
"//ui/android:ui_java",
]
......@@ -75,6 +76,8 @@ android_apk("webview_instrumentation_apk") {
":libstandalonelibwebviewchromium",
]
loadable_modules = [ "$root_out_dir/libcrashpad_handler.so" ]
native_lib_version_rule = "//build/util:chrome_version_json"
_native_lib_file =
rebase_path("$root_gen_dir/CHROME_VERSION.json", root_build_dir)
......
......@@ -210,7 +210,8 @@ def _AddNativeLibraries(out_apk, native_libs, android_abi, uncompress):
compress = None
if (uncompress and os.path.splitext(basename)[1] == '.so'
and 'android_linker' not in basename
and 'clang_rt' not in basename):
and 'clang_rt' not in basename
and 'crashpad_handler' not in basename):
compress = False
# Add prefix to prevent android install from extracting upon install.
if has_crazy_linker:
......
......@@ -1168,6 +1168,7 @@ if (!android_64bit_target_cpu ||
deps = [
"//android_webview:common",
"//chrome:chrome_android_core",
"//components/crash/android:crashpad_main",
]
configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
......
......@@ -87,6 +87,8 @@ template("chrome_public_common_apk_or_module_tmpl") {
_is_modern = defined(invoker.is_modern) && invoker.is_modern
assert(_is_modern || !_is_modern) # Mark as used.
_is_monochrome = defined(invoker.is_monochrome) && invoker.is_monochrome
if (defined(invoker.enable_multidex)) {
_enable_multidex = invoker.enable_multidex
} else {
......@@ -119,6 +121,16 @@ template("chrome_public_common_apk_or_module_tmpl") {
aapt_locale_whitelist = locales - android_chrome_omitted_locales
}
if (!_is_monochrome) {
deps += [
"//third_party/crashpad/crashpad/handler:crashpad_handler_named_as_so",
]
if (!defined(loadable_modules)) {
loadable_modules = []
}
loadable_modules += [ "$root_out_dir/libcrashpad_handler.so" ]
}
if (_enable_multidex) {
enable_multidex = true
if (_target_type == "android_apk") {
......@@ -195,6 +207,8 @@ template("monochrome_public_common_apk_or_module_tmpl") {
_enable_multidex = is_java_debug || multidex_in_release
}
chrome_public_common_apk_or_module_tmpl(target_name) {
is_monochrome = true
# Always build 64-bit //android_webview:monochrome because Chrome runs
# in 32-bit mode.
if (android_64bit_target_cpu) {
......@@ -242,6 +256,7 @@ template("monochrome_public_common_apk_or_module_tmpl") {
"//chrome/android:chrome_public_non_pak_assets",
"//chrome/android:monochrome_pak_assets",
"//chrome/android/monochrome:monochrome_license_provider_java",
"//components/crash/android:handler_java",
]
if (_enable_multidex && invoker.target_type == "android_apk" &&
......
......@@ -648,8 +648,11 @@ if (is_android) {
"//base:base_java",
"//chromecast/android:libcast_shell_android",
"//chromecast/browser/android:cast_shell_java",
"//third_party/crashpad/crashpad/handler:crashpad_handler_named_as_so",
]
loadable_modules = [ "$root_out_dir/libcrashpad_handler.so" ]
command_line_flags_file = "castshell-command-line"
}
}
......@@ -4,9 +4,10 @@
import("//build/config/android/rules.gni")
_jni_sources =
[ "java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java",
"java/src/org/chromium/components/crash/browser/CrashDumpManager.java" ]
_jni_sources = [
"java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java",
"java/src/org/chromium/components/crash/browser/CrashDumpManager.java",
]
generate_jni("jni_headers") {
sources = _jni_sources
......@@ -31,3 +32,31 @@ android_library("javatests") {
]
java_files = [ "javatests/src/org/chromium/components/crash/browser/CrashDumpManagerTest.java" ]
}
_java_handler_jni_sources =
[ "java/src/org/chromium/components/crash/browser/CrashpadMain.java" ]
generate_jni("java_handler_jni_headers") {
sources = _java_handler_jni_sources
jni_package = "crashpad"
}
android_library("handler_java") {
deps = [
"//base:base_java",
]
java_files = _java_handler_jni_sources
}
static_library("crashpad_main") {
sources = [
"crashpad_main.cc",
]
deps = [
":java_handler_jni_headers",
"//base",
"//third_party/crashpad/crashpad/client",
"//third_party/crashpad/crashpad/handler",
]
}
include_rules = [
"+jni",
]
\ No newline at end of file
"+third_party/crashpad",
]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "jni/CrashpadMain_jni.h"
#include "third_party/crashpad/crashpad/client/client_argv_handling.h"
#include "third_party/crashpad/crashpad/handler/handler_main.h"
namespace crashpad {
static void JNI_CrashpadMain_CrashpadMain(
JNIEnv* env,
const base::android::JavaParamRef<jclass>& jcaller,
const base::android::JavaParamRef<jobjectArray>& j_argv) {
std::vector<std::string> argv_strings;
base::android::AppendJavaStringArrayToStringVector(env, j_argv,
&argv_strings);
std::vector<const char*> argv;
StringVectorToCStringVector(argv_strings, &argv);
HandlerMain(argv.size() - 1, const_cast<char**>(argv.data()), nullptr);
}
} // namespace crashpad
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.components.crash.browser;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.UsedByReflection;
import org.chromium.base.library_loader.NativeLibraries;
@JNINamespace("crashpad")
final class CrashpadMain {
@UsedByReflection("crashpad_linux.cc")
public static void main(String[] argv) {
try {
for (String library : NativeLibraries.LIBRARIES) {
System.loadLibrary(library);
}
} catch (UnsatisfiedLinkError e) {
throw new RuntimeException(e);
}
nativeCrashpadMain(argv);
}
private static native void nativeCrashpadMain(String[] argv);
}
......@@ -26,6 +26,7 @@
#include "content/public/common/content_descriptors.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/snapshot/sanitized/sanitization_information.h"
#include "third_party/crashpad/crashpad/util/linux/exception_handler_client.h"
......@@ -36,6 +37,7 @@
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
#include "base/android/java_exception_reporter.h"
#include "base/android/path_utils.h"
#endif // OS_ANDROID
namespace crashpad {
......@@ -82,6 +84,12 @@ class SandboxedHandler {
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;
iov.iov_base = &signo;
iov.iov_len = sizeof(signo);
......@@ -186,9 +194,64 @@ void SetBuildInfoAnnotations(std::map<std::string, std::string>* annotations) {
}
}
#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"
#else
#error "Unsupported target abi"
#endif
// 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) {
DCHECK(result->empty());
base::FilePath apk_path;
if (!base::android::GetPathToBaseApk(&apk_path)) {
return false;
}
std::unique_ptr<base::Environment> env(base::Environment::Create());
static constexpr char kClasspathVar[] = "CLASSPATH";
std::string classpath;
env->GetVar(kClasspathVar, &classpath);
classpath = apk_path.value() + ":" + classpath;
static constexpr char kLdLibraryPathVar[] = "LD_LIBRARY_PATH";
std::string library_path;
env->GetVar(kLdLibraryPathVar, &library_path);
library_path = apk_path.value() + "!/lib/" CURRENT_ABI ":" + library_path;
result->push_back("CLASSPATH=" + classpath);
result->push_back("LD_LIBRARY_PATH=" + library_path);
for (char** envp = environ; *envp != nullptr; ++envp) {
if ((strncmp(*envp, kClasspathVar, strlen(kClasspathVar)) == 0 &&
(*envp)[strlen(kClasspathVar)] == '=') ||
(strncmp(*envp, kLdLibraryPathVar, strlen(kLdLibraryPathVar)) == 0 &&
(*envp)[strlen(kLdLibraryPathVar)] == '=')) {
continue;
}
result->push_back(*envp);
}
return true;
}
const char kCrashpadJavaMain[] =
"org.chromium.components.crash.browser.CrashpadMain";
#endif // OS_ANDROID
bool BuildHandlerArgs(base::FilePath* database_path,
void BuildHandlerArgs(base::FilePath* database_path,
base::FilePath* metrics_path,
std::string* url,
std::map<std::string, std::string>* process_annotations,
......@@ -241,7 +304,6 @@ bool BuildHandlerArgs(base::FilePath* database_path,
// so that minidumps produced by Crashpad's generate_dump tool will
// contain these annotations.
arguments->push_back("--monitor-self-annotation=ptype=crashpad-handler");
return true;
}
bool GetHandlerPath(base::FilePath* exe_dir, base::FilePath* handler_path) {
......@@ -291,24 +353,18 @@ class HandlerStarter {
}
base::FilePath Initialize() {
base::FilePath exe_dir;
base::FilePath handler_path;
if (!GetHandlerPath(&exe_dir, &handler_path)) {
return base::FilePath();
}
if (!SetLdLibraryPath(exe_dir)) {
return base::FilePath();
}
base::FilePath database_path;
base::FilePath metrics_path;
std::string url;
std::map<std::string, std::string> process_annotations;
std::vector<std::string> arguments;
if (!BuildHandlerArgs(&database_path, &metrics_path, &url,
&process_annotations, &arguments)) {
return base::FilePath();
BuildHandlerArgs(&database_path, &metrics_path, &url, &process_annotations,
&arguments);
base::FilePath exe_dir;
base::FilePath handler_path;
if (!GetHandlerPath(&exe_dir, &handler_path)) {
return database_path;
}
if (crashpad::SetSanitizationInfo(&browser_sanitization_info_)) {
......@@ -316,6 +372,26 @@ class HandlerStarter {
&browser_sanitization_info_));
}
#if defined(OS_ANDROID)
if (!base::PathExists(handler_path)) {
use_java_handler_ = true;
std::vector<std::string> env;
if (!BuildEnvironmentWithApk(&env)) {
return database_path;
}
bool result = GetCrashpadClient().StartJavaHandlerAtCrash(
kCrashpadJavaMain, &env, database_path, metrics_path, url,
process_annotations, arguments);
DCHECK(result);
return database_path;
}
#endif
if (!SetLdLibraryPath(exe_dir)) {
return database_path;
}
bool result = GetCrashpadClient().StartHandlerAtCrash(
handler_path, database_path, metrics_path, url, process_annotations,
arguments);
......@@ -324,23 +400,35 @@ class HandlerStarter {
}
bool StartHandlerForClient(int fd) {
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(&database_path, &metrics_path, &url, &process_annotations,
&arguments);
base::FilePath exe_dir;
base::FilePath handler_path;
if (!GetHandlerPath(&exe_dir, &handler_path)) {
return false;
}
if (!SetLdLibraryPath(exe_dir)) {
return false;
#if defined(OS_ANDROID)
if (use_java_handler_) {
std::vector<std::string> env;
if (!BuildEnvironmentWithApk(&env)) {
return false;
}
bool result = GetCrashpadClient().StartJavaHandlerForClient(
kCrashpadJavaMain, &env, database_path, metrics_path, url,
process_annotations, arguments, fd);
return result;
}
#endif
base::FilePath database_path;
base::FilePath metrics_path;
std::string url;
std::map<std::string, std::string> process_annotations;
std::vector<std::string> arguments;
if (!BuildHandlerArgs(&database_path, &metrics_path, &url,
&process_annotations, &arguments)) {
if (!SetLdLibraryPath(exe_dir)) {
return false;
}
......@@ -354,6 +442,9 @@ class HandlerStarter {
~HandlerStarter() = delete;
crashpad::SanitizationInformation browser_sanitization_info_;
#if defined(OS_ANDROID)
bool use_java_handler_ = false;
#endif
DISALLOW_COPY_AND_ASSIGN(HandlerStarter);
};
......
......@@ -181,6 +181,7 @@ android_apk("content_shell_apk") {
"//media/capture/video/android:capture_java",
"//net/android:net_java",
"//services/shape_detection:shape_detection_java",
"//third_party/crashpad/crashpad/handler:crashpad_handler_named_as_so",
"//third_party/mesa_headers",
"//ui/android:ui_java",
]
......@@ -188,6 +189,7 @@ android_apk("content_shell_apk") {
android_manifest = content_shell_manifest
android_manifest_dep = ":content_shell_manifest"
shared_libraries = [ ":libcontent_shell_content_view" ]
loadable_modules = [ "$root_out_dir/libcrashpad_handler.so" ]
command_line_flags_file = "content-shell-command-line"
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment