blob: 84f83e9cb7ee8ba8c4c61c007cd71eadd6cf8c7e [file] [log] [blame]
// Copyright 2015 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 "android_webview/common/crash_reporter/aw_crash_reporter_client.h"
#include <stdint.h>
#include "android_webview/common/aw_channel.h"
#include "android_webview/common/aw_descriptors.h"
#include "android_webview/common/aw_paths.h"
#include "android_webview/common/aw_switches.h"
#include "android_webview/common/crash_reporter/crash_keys.h"
#include "base/android/build_info.h"
#include "base/base_paths_android.h"
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/scoped_native_library.h"
#include "build/build_config.h"
#include "components/crash/content/app/crash_reporter_client.h"
#include "components/crash/content/app/crashpad.h"
#include "components/version_info/version_info.h"
#include "components/version_info/version_info_values.h"
namespace android_webview {
namespace crash_reporter {
namespace {
class AwCrashReporterClient : public ::crash_reporter::CrashReporterClient {
public:
AwCrashReporterClient() {}
// crash_reporter::CrashReporterClient implementation.
bool IsRunningUnattended() override { return false; }
bool GetCollectStatsConsent() override {
// TODO(jperaza): Crashpad uses GetCollectStatsConsent() to enable or
// disable upload of crash reports. However, Crashpad does not yet support
// upload on Android, so this return value currently has no effect and
// WebView's own uploader will determine consent before uploading. If and
// when Crashpad supports upload on Android, consent can be determined here,
// or WebView can continue uploading reports itself.
return false;
}
void GetProductNameAndVersion(std::string* product_name,
std::string* version,
std::string* channel) override {
*product_name = "AndroidWebView";
*version = PRODUCT_VERSION;
*channel =
version_info::GetChannelString(android_webview::GetChannelOrStable());
}
bool GetCrashDumpLocation(base::FilePath* crash_dir) override {
return base::PathService::Get(android_webview::DIR_CRASH_DUMPS, crash_dir);
}
void GetSanitizationInformation(const char* const** annotations_whitelist,
void** target_module,
bool* sanitize_stacks) override {
*annotations_whitelist = crash_keys::kWebViewCrashKeyWhiteList;
#if defined(COMPONENT_BUILD)
*target_module = nullptr;
#else
*target_module = reinterpret_cast<void*>(&EnableCrashReporter);
#endif
*sanitize_stacks = true;
}
unsigned int GetCrashDumpPercentageForWebView() override { return 100; }
bool GetBrowserProcessType(std::string* ptype) override {
*ptype = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kWebViewSandboxedRenderer)
? "browser"
: "webview";
return true;
}
private:
DISALLOW_COPY_AND_ASSIGN(AwCrashReporterClient);
};
base::LazyInstance<AwCrashReporterClient>::Leaky g_crash_reporter_client =
LAZY_INSTANCE_INITIALIZER;
#if defined(ARCH_CPU_X86_FAMILY)
bool SafeToUseSignalHandler() {
// N+ shared library namespacing means that we are unable to dlopen
// libnativebridge (because it isn't in the NDK). However we know
// that, were we able to, the tests below would pass, so just return
// true here.
if (base::android::BuildInfo::GetInstance()->sdk_int() >=
base::android::SDK_VERSION_NOUGAT) {
return true;
}
// On X86/64 there are binary translators that handle SIGSEGV in userspace and
// may get chained after our handler - see http://crbug.com/477444
// We attempt to detect this to work out when it's safe to install breakpad.
// If anything doesn't seem right we assume it's not safe.
// type and mangled name of android::NativeBridgeInitialized
typedef bool (*InitializedFunc)();
const char kInitializedSymbol[] = "_ZN7android23NativeBridgeInitializedEv";
// type and mangled name of android::NativeBridgeGetVersion
typedef uint32_t (*VersionFunc)();
const char kVersionSymbol[] = "_ZN7android22NativeBridgeGetVersionEv";
base::ScopedNativeLibrary lib_native_bridge(
base::FilePath("libnativebridge.so"));
if (!lib_native_bridge.is_valid()) {
DLOG(WARNING) << "Couldn't load libnativebridge";
return false;
}
InitializedFunc NativeBridgeInitialized = reinterpret_cast<InitializedFunc>(
lib_native_bridge.GetFunctionPointer(kInitializedSymbol));
if (NativeBridgeInitialized == nullptr) {
DLOG(WARNING) << "Couldn't tell if native bridge initialized";
return false;
}
if (!NativeBridgeInitialized()) {
// Native process, safe to use breakpad.
return true;
}
VersionFunc NativeBridgeGetVersion = reinterpret_cast<VersionFunc>(
lib_native_bridge.GetFunctionPointer(kVersionSymbol));
if (NativeBridgeGetVersion == nullptr) {
DLOG(WARNING) << "Couldn't get native bridge version";
return false;
}
uint32_t version = NativeBridgeGetVersion();
if (version >= 2) {
// Native bridge at least version 2, safe to use breakpad.
return true;
} else {
DLOG(WARNING) << "Native bridge ver=" << version << "; too low";
return false;
}
}
#endif
} // namespace
void EnableCrashReporter(const std::string& process_type) {
static bool enabled;
if (enabled) {
NOTREACHED() << "EnableCrashReporter called more than once";
return;
}
enabled = true;
#if defined(ARCH_CPU_X86_FAMILY)
if (!SafeToUseSignalHandler()) {
LOG(WARNING) << "Can't use breakpad to handle WebView crashes";
return;
}
#endif
AwCrashReporterClient* client = g_crash_reporter_client.Pointer();
::crash_reporter::SetCrashReporterClient(client);
::crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
}
bool GetCrashDumpLocation(base::FilePath* crash_dir) {
return g_crash_reporter_client.Get().GetCrashDumpLocation(crash_dir);
}
} // namespace crash_reporter
} // namespace android_webview