| // 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 |