mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-02-18 05:00:48 +01:00
Improve crashpad integration (issue #1995)
- Crash reporting is enabled and configured using a "crash_reporter.cfg" file. See comments in include/cef_crash_util.h and tools/crash_server.py for usage.
This commit is contained in:
parent
c990b5d877
commit
a834487177
14
BUILD.gn
14
BUILD.gn
@ -426,6 +426,8 @@ static_library("libcef_static") {
|
|||||||
"libcef/common/content_client.h",
|
"libcef/common/content_client.h",
|
||||||
"libcef/common/crash_reporter_client.cc",
|
"libcef/common/crash_reporter_client.cc",
|
||||||
"libcef/common/crash_reporter_client.h",
|
"libcef/common/crash_reporter_client.h",
|
||||||
|
"libcef/common/crash_reporting.cc",
|
||||||
|
"libcef/common/crash_reporting.h",
|
||||||
"libcef/common/drag_data_impl.cc",
|
"libcef/common/drag_data_impl.cc",
|
||||||
"libcef/common/drag_data_impl.h",
|
"libcef/common/drag_data_impl.h",
|
||||||
"libcef/common/extensions/chrome_generated_schemas.cc",
|
"libcef/common/extensions/chrome_generated_schemas.cc",
|
||||||
@ -558,6 +560,11 @@ static_library("libcef_static") {
|
|||||||
"//third_party/WebKit/public/web",
|
"//third_party/WebKit/public/web",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
public_deps = [
|
||||||
|
# Bring in feature flag defines.
|
||||||
|
"//cef/libcef/features",
|
||||||
|
]
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
# Generate pack files and associated CEF header files.
|
# Generate pack files and associated CEF header files.
|
||||||
":make_pack_header_resources",
|
":make_pack_header_resources",
|
||||||
@ -679,6 +686,8 @@ static_library("libcef_static") {
|
|||||||
"libcef/browser/osr/browser_platform_delegate_osr_win.cc",
|
"libcef/browser/osr/browser_platform_delegate_osr_win.cc",
|
||||||
"libcef/browser/osr/browser_platform_delegate_osr_win.h",
|
"libcef/browser/osr/browser_platform_delegate_osr_win.h",
|
||||||
"libcef/browser/osr/render_widget_host_view_osr_win.cc",
|
"libcef/browser/osr/render_widget_host_view_osr_win.cc",
|
||||||
|
"libcef/common/crash_reporting_win.cc",
|
||||||
|
"libcef/common/crash_reporting_win.h",
|
||||||
|
|
||||||
# Part of //chrome/utility.
|
# Part of //chrome/utility.
|
||||||
"//chrome/utility/printing_handler.cc",
|
"//chrome/utility/printing_handler.cc",
|
||||||
@ -687,7 +696,6 @@ static_library("libcef_static") {
|
|||||||
|
|
||||||
deps += [
|
deps += [
|
||||||
"//chrome_elf",
|
"//chrome_elf",
|
||||||
"//components/crash/content/app:run_as_crashpad_handler",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,6 +738,10 @@ static_library("libcef_static") {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_win || is_mac) {
|
||||||
|
deps += [ "//third_party/crashpad/crashpad/handler:handler_lib" ]
|
||||||
|
}
|
||||||
|
|
||||||
if (use_x11) {
|
if (use_x11) {
|
||||||
deps += [ "//ui/events/devices/x11" ]
|
deps += [ "//ui/events/devices/x11" ]
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
'include/cef_command_line.h',
|
'include/cef_command_line.h',
|
||||||
'include/cef_context_menu_handler.h',
|
'include/cef_context_menu_handler.h',
|
||||||
'include/cef_cookie.h',
|
'include/cef_cookie.h',
|
||||||
|
'include/cef_crash_util.h',
|
||||||
'include/cef_dialog_handler.h',
|
'include/cef_dialog_handler.h',
|
||||||
'include/cef_display_handler.h',
|
'include/cef_display_handler.h',
|
||||||
'include/cef_dom.h',
|
'include/cef_dom.h',
|
||||||
@ -108,6 +109,7 @@
|
|||||||
'include/capi/cef_command_line_capi.h',
|
'include/capi/cef_command_line_capi.h',
|
||||||
'include/capi/cef_context_menu_handler_capi.h',
|
'include/capi/cef_context_menu_handler_capi.h',
|
||||||
'include/capi/cef_cookie_capi.h',
|
'include/capi/cef_cookie_capi.h',
|
||||||
|
'include/capi/cef_crash_util_capi.h',
|
||||||
'include/capi/cef_dialog_handler_capi.h',
|
'include/capi/cef_dialog_handler_capi.h',
|
||||||
'include/capi/cef_display_handler_capi.h',
|
'include/capi/cef_display_handler_capi.h',
|
||||||
'include/capi/cef_dom_capi.h',
|
'include/capi/cef_dom_capi.h',
|
||||||
|
@ -193,6 +193,8 @@
|
|||||||
'tests/cefclient/browser/bytes_write_handler.cc',
|
'tests/cefclient/browser/bytes_write_handler.cc',
|
||||||
'tests/cefclient/browser/bytes_write_handler.h',
|
'tests/cefclient/browser/bytes_write_handler.h',
|
||||||
'tests/cefclient/browser/client_app_delegates_browser.cc',
|
'tests/cefclient/browser/client_app_delegates_browser.cc',
|
||||||
|
'tests/cefclient/browser/client_browser.cc',
|
||||||
|
'tests/cefclient/browser/client_browser.h',
|
||||||
'tests/cefclient/browser/client_handler.cc',
|
'tests/cefclient/browser/client_handler.cc',
|
||||||
'tests/cefclient/browser/client_handler.h',
|
'tests/cefclient/browser/client_handler.h',
|
||||||
'tests/cefclient/browser/client_handler_osr.cc',
|
'tests/cefclient/browser/client_handler_osr.cc',
|
||||||
|
136
include/capi/cef_crash_util_capi.h
Normal file
136
include/capi/cef_crash_util_capi.h
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// Copyright (c) 2017 Marshall A. Greenblatt. All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the name Chromium Embedded
|
||||||
|
// Framework nor the names of its contributors may be used to endorse
|
||||||
|
// or promote products derived from this software without specific prior
|
||||||
|
// written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This file was generated by the CEF translator tool and should not edited
|
||||||
|
// by hand. See the translator.README.txt file in the tools directory for
|
||||||
|
// more information.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef CEF_INCLUDE_CAPI_CEF_CRASH_UTIL_CAPI_H_
|
||||||
|
#define CEF_INCLUDE_CAPI_CEF_CRASH_UTIL_CAPI_H_
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "include/capi/cef_base_capi.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
// Crash reporting is configured using an INI-style config file named
|
||||||
|
// "crash_reporter.cfg". On Windows and Linux this file must be placed next to
|
||||||
|
// the main application executable. On macOS this file must be placed in the
|
||||||
|
// top-level app bundle Resources directory (e.g.
|
||||||
|
// "<appname>.app/Contents/Resources"). File contents are as follows:
|
||||||
|
//
|
||||||
|
// # Comments start with a hash character and must be on their own line.
|
||||||
|
//
|
||||||
|
// [Config]
|
||||||
|
// AppName=<Windows only; App-specific folder name component for storing crash
|
||||||
|
// information; default to "CEF">
|
||||||
|
// ExternalHandler=<Windows only; Name of the external handler exe to use
|
||||||
|
// instead of re-launching the main exe; default to empty>
|
||||||
|
// ServerURL=<crash server URL; default to empty>
|
||||||
|
// RateLimitEnabled=<True if uploads should be rate limited; default to true>
|
||||||
|
// MaxUploadsPerDay=<Max uploads per 24 hours, used if rate limit is enabled;
|
||||||
|
// default to 5>
|
||||||
|
// MaxDatabaseSizeInMb=<Total crash report disk usage greater than this value
|
||||||
|
// will cause older reports to be deleted; default to 20>
|
||||||
|
// MaxDatabaseAgeInDays=<Crash reports older than this value will be deleted;
|
||||||
|
// default to 5>
|
||||||
|
//
|
||||||
|
// [CrashKeys]
|
||||||
|
// my_key1=<small|medium|large>
|
||||||
|
// my_key2=<small|medium|large>
|
||||||
|
//
|
||||||
|
// Config section:
|
||||||
|
//
|
||||||
|
// If "AppName" is set on Windows then crash report information (metrics,
|
||||||
|
// database and dumps) will be stored locally on disk under the
|
||||||
|
// "C:\Users\[CurrentUser]\AppData\Local\[AppName]\User Data" folder. On other
|
||||||
|
// platforms the CefSettings.user_data_path value will be used.
|
||||||
|
//
|
||||||
|
// If "ExternalHandler" is set on Windows then the specified exe will be
|
||||||
|
// launched as the crashpad-handler instead of re-launching the main process
|
||||||
|
// exe. The value can be an absolute path or a path relative to the main exe
|
||||||
|
// directory. On Linux the CefSettings.browser_subprocess_path value will be
|
||||||
|
// used. On macOS the existing subprocess app bundle will be used.
|
||||||
|
//
|
||||||
|
// If "ServerURL" is set then crashes will be uploaded as a multi-part POST
|
||||||
|
// request to the specified URL. Otherwise, reports will only be stored locally
|
||||||
|
// on disk.
|
||||||
|
//
|
||||||
|
// If "RateLimitEnabled" is set to true (1) then crash report uploads will be
|
||||||
|
// rate limited as follows:
|
||||||
|
// 1. If "MaxUploadsPerDay" is set to a positive value then at most the
|
||||||
|
// specified number of crashes will be uploaded in each 24 hour period.
|
||||||
|
// 2. If crash upload fails due to a network or server error then an
|
||||||
|
// incremental backoff delay up to a maximum of 24 hours will be applied for
|
||||||
|
// retries.
|
||||||
|
// 3. If a backoff delay is applied and "MaxUploadsPerDay" is > 1 then the
|
||||||
|
// "MaxUploadsPerDay" value will be reduced to 1 until the client is
|
||||||
|
// restarted. This helps to avoid an upload flood when the network or
|
||||||
|
// server error is resolved.
|
||||||
|
// Rate limiting is not supported on Linux.
|
||||||
|
//
|
||||||
|
// If "MaxDatabaseSizeInMb" is set to a positive value then crash report storage
|
||||||
|
// on disk will be limited to that size in megabytes. For example, on Windows
|
||||||
|
// each dump is about 600KB so a "MaxDatabaseSizeInMb" value of 20 equates to
|
||||||
|
// about 34 crash reports stored on disk. Not supported on Linux.
|
||||||
|
//
|
||||||
|
// If "MaxDatabaseAgeInDays" is set to a positive value then crash reports older
|
||||||
|
// than the specified age in days will be deleted. Not supported on Linux.
|
||||||
|
//
|
||||||
|
// CrashKeys section:
|
||||||
|
//
|
||||||
|
// Any number of crash keys can be specified for use by the application. Crash
|
||||||
|
// key values will be truncated based on the specified size (small = 63 bytes,
|
||||||
|
// medium = 252 bytes, large = 1008 bytes). The value of crash keys can be set
|
||||||
|
// from any thread or process using the CefSetCrashKeyValue function. These
|
||||||
|
// key/value pairs will be sent to the crash server along with the crash dump
|
||||||
|
// file. Medium and large values will be chunked for submission. For example, if
|
||||||
|
// your key is named "mykey" then the value will be broken into ordered chunks
|
||||||
|
// and submitted using keys named "mykey-1", "mykey-2", etc.
|
||||||
|
///
|
||||||
|
CEF_EXPORT int cef_crash_reporting_enabled();
|
||||||
|
|
||||||
|
///
|
||||||
|
// Sets or clears a specific key-value pair from the crash metadata.
|
||||||
|
///
|
||||||
|
CEF_EXPORT void cef_set_crash_key_value(const cef_string_t* key,
|
||||||
|
const cef_string_t* value);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CEF_INCLUDE_CAPI_CEF_CRASH_UTIL_CAPI_H_
|
128
include/cef_crash_util.h
Normal file
128
include/cef_crash_util.h
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the name Chromium Embedded
|
||||||
|
// Framework nor the names of its contributors may be used to endorse
|
||||||
|
// or promote products derived from this software without specific prior
|
||||||
|
// written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// The contents of this file must follow a specific format in order to
|
||||||
|
// support the CEF translator tool. See the translator.README.txt file in the
|
||||||
|
// tools directory for more information.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef CEF_INCLUDE_CEF_CRASH_UTIL_H_
|
||||||
|
#define CEF_INCLUDE_CEF_CRASH_UTIL_H_
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
///
|
||||||
|
// Crash reporting is configured using an INI-style config file named
|
||||||
|
// "crash_reporter.cfg". On Windows and Linux this file must be placed next to
|
||||||
|
// the main application executable. On macOS this file must be placed in the
|
||||||
|
// top-level app bundle Resources directory (e.g.
|
||||||
|
// "<appname>.app/Contents/Resources"). File contents are as follows:
|
||||||
|
//
|
||||||
|
// # Comments start with a hash character and must be on their own line.
|
||||||
|
//
|
||||||
|
// [Config]
|
||||||
|
// AppName=<Windows only; App-specific folder name component for storing crash
|
||||||
|
// information; default to "CEF">
|
||||||
|
// ExternalHandler=<Windows only; Name of the external handler exe to use
|
||||||
|
// instead of re-launching the main exe; default to empty>
|
||||||
|
// ServerURL=<crash server URL; default to empty>
|
||||||
|
// RateLimitEnabled=<True if uploads should be rate limited; default to true>
|
||||||
|
// MaxUploadsPerDay=<Max uploads per 24 hours, used if rate limit is enabled;
|
||||||
|
// default to 5>
|
||||||
|
// MaxDatabaseSizeInMb=<Total crash report disk usage greater than this value
|
||||||
|
// will cause older reports to be deleted; default to 20>
|
||||||
|
// MaxDatabaseAgeInDays=<Crash reports older than this value will be deleted;
|
||||||
|
// default to 5>
|
||||||
|
//
|
||||||
|
// [CrashKeys]
|
||||||
|
// my_key1=<small|medium|large>
|
||||||
|
// my_key2=<small|medium|large>
|
||||||
|
//
|
||||||
|
// Config section:
|
||||||
|
//
|
||||||
|
// If "AppName" is set on Windows then crash report information (metrics,
|
||||||
|
// database and dumps) will be stored locally on disk under the
|
||||||
|
// "C:\Users\[CurrentUser]\AppData\Local\[AppName]\User Data" folder. On other
|
||||||
|
// platforms the CefSettings.user_data_path value will be used.
|
||||||
|
//
|
||||||
|
// If "ExternalHandler" is set on Windows then the specified exe will be
|
||||||
|
// launched as the crashpad-handler instead of re-launching the main process
|
||||||
|
// exe. The value can be an absolute path or a path relative to the main exe
|
||||||
|
// directory. On Linux the CefSettings.browser_subprocess_path value will be
|
||||||
|
// used. On macOS the existing subprocess app bundle will be used.
|
||||||
|
//
|
||||||
|
// If "ServerURL" is set then crashes will be uploaded as a multi-part POST
|
||||||
|
// request to the specified URL. Otherwise, reports will only be stored locally
|
||||||
|
// on disk.
|
||||||
|
//
|
||||||
|
// If "RateLimitEnabled" is set to true then crash report uploads will be rate
|
||||||
|
// limited as follows:
|
||||||
|
// 1. If "MaxUploadsPerDay" is set to a positive value then at most the
|
||||||
|
// specified number of crashes will be uploaded in each 24 hour period.
|
||||||
|
// 2. If crash upload fails due to a network or server error then an
|
||||||
|
// incremental backoff delay up to a maximum of 24 hours will be applied for
|
||||||
|
// retries.
|
||||||
|
// 3. If a backoff delay is applied and "MaxUploadsPerDay" is > 1 then the
|
||||||
|
// "MaxUploadsPerDay" value will be reduced to 1 until the client is
|
||||||
|
// restarted. This helps to avoid an upload flood when the network or
|
||||||
|
// server error is resolved.
|
||||||
|
// Rate limiting is not supported on Linux.
|
||||||
|
//
|
||||||
|
// If "MaxDatabaseSizeInMb" is set to a positive value then crash report storage
|
||||||
|
// on disk will be limited to that size in megabytes. For example, on Windows
|
||||||
|
// each dump is about 600KB so a "MaxDatabaseSizeInMb" value of 20 equates to
|
||||||
|
// about 34 crash reports stored on disk. Not supported on Linux.
|
||||||
|
//
|
||||||
|
// If "MaxDatabaseAgeInDays" is set to a positive value then crash reports older
|
||||||
|
// than the specified age in days will be deleted. Not supported on Linux.
|
||||||
|
//
|
||||||
|
// CrashKeys section:
|
||||||
|
//
|
||||||
|
// Any number of crash keys can be specified for use by the application. Crash
|
||||||
|
// key values will be truncated based on the specified size (small = 63 bytes,
|
||||||
|
// medium = 252 bytes, large = 1008 bytes). The value of crash keys can be set
|
||||||
|
// from any thread or process using the CefSetCrashKeyValue function. These
|
||||||
|
// key/value pairs will be sent to the crash server along with the crash dump
|
||||||
|
// file. Medium and large values will be chunked for submission. For example,
|
||||||
|
// if your key is named "mykey" then the value will be broken into ordered
|
||||||
|
// chunks and submitted using keys named "mykey-1", "mykey-2", etc.
|
||||||
|
///
|
||||||
|
/*--cef()--*/
|
||||||
|
bool CefCrashReportingEnabled();
|
||||||
|
|
||||||
|
#include "include/cef_base.h"
|
||||||
|
|
||||||
|
///
|
||||||
|
// Sets or clears a specific key-value pair from the crash metadata.
|
||||||
|
///
|
||||||
|
/*--cef()--*/
|
||||||
|
void CefSetCrashKeyValue(const CefString& key, const CefString& value);
|
||||||
|
|
||||||
|
#endif // CEF_INCLUDE_CEF_CRASH_UTIL_H_
|
@ -89,6 +89,7 @@
|
|||||||
|
|
||||||
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
||||||
#include "base/debug/leak_annotations.h"
|
#include "base/debug/leak_annotations.h"
|
||||||
|
#include "chrome/common/chrome_paths.h"
|
||||||
#include "components/crash/content/app/breakpad_linux.h"
|
#include "components/crash/content/app/breakpad_linux.h"
|
||||||
#include "components/crash/content/browser/crash_handler_host_linux.h"
|
#include "components/crash/content/browser/crash_handler_host_linux.h"
|
||||||
#include "content/public/common/content_descriptors.h"
|
#include "content/public/common/content_descriptors.h"
|
||||||
@ -317,14 +318,15 @@ class CefQuotaPermissionContext : public content::QuotaPermissionContext {
|
|||||||
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
||||||
breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
|
breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
|
||||||
const std::string& process_type) {
|
const std::string& process_type) {
|
||||||
base::FilePath dumps_path =
|
base::FilePath dumps_path;
|
||||||
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
|
PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
|
||||||
switches::kCrashDumpsDir);
|
|
||||||
{
|
{
|
||||||
ANNOTATE_SCOPED_MEMORY_LEAK;
|
ANNOTATE_SCOPED_MEMORY_LEAK;
|
||||||
|
// Uploads will only occur if a non-empty crash URL is specified in
|
||||||
|
// CefMainDelegate::InitCrashReporter.
|
||||||
breakpad::CrashHandlerHostLinux* crash_handler =
|
breakpad::CrashHandlerHostLinux* crash_handler =
|
||||||
new breakpad::CrashHandlerHostLinux(
|
new breakpad::CrashHandlerHostLinux(
|
||||||
process_type, dumps_path, false);
|
process_type, dumps_path, true /* upload */);
|
||||||
crash_handler->StartUploaderThread();
|
crash_handler->StartUploaderThread();
|
||||||
return crash_handler;
|
return crash_handler;
|
||||||
}
|
}
|
||||||
@ -618,11 +620,7 @@ void CefContentBrowserClient::AppendExtraCommandLineSwitches(
|
|||||||
// Propagate the following switches to all command lines (along with any
|
// Propagate the following switches to all command lines (along with any
|
||||||
// associated values) if present in the browser command line.
|
// associated values) if present in the browser command line.
|
||||||
static const char* const kSwitchNames[] = {
|
static const char* const kSwitchNames[] = {
|
||||||
#if !defined(OS_WIN)
|
|
||||||
switches::kCrashDumpsDir,
|
|
||||||
#endif
|
|
||||||
switches::kDisablePackLoading,
|
switches::kDisablePackLoading,
|
||||||
switches::kEnableCrashReporter,
|
|
||||||
switches::kLang,
|
switches::kLang,
|
||||||
switches::kLocalesDirPath,
|
switches::kLocalesDirPath,
|
||||||
switches::kLogFile,
|
switches::kLogFile,
|
||||||
|
@ -31,14 +31,18 @@
|
|||||||
#include "ui/base/ui_base_switches.h"
|
#include "ui/base/ui_base_switches.h"
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "chrome_elf/chrome_elf_main.h"
|
#include "chrome_elf/chrome_elf_main.h"
|
||||||
#include "content/public/app/sandbox_helper_win.h"
|
#include "content/public/app/sandbox_helper_win.h"
|
||||||
#include "components/crash/content/app/crash_switches.h"
|
|
||||||
#include "components/crash/content/app/crashpad.h"
|
#include "components/crash/content/app/crashpad.h"
|
||||||
#include "components/crash/content/app/run_as_crashpad_handler_win.h"
|
|
||||||
#include "sandbox/win/src/sandbox_types.h"
|
#include "sandbox/win/src/sandbox_types.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX) || defined(OS_WIN)
|
||||||
|
#include "components/crash/content/app/crash_switches.h"
|
||||||
|
#include "third_party/crashpad/crashpad/handler/handler_main.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
CefContext* g_context = NULL;
|
CefContext* g_context = NULL;
|
||||||
@ -73,7 +77,7 @@ void DisableFMA3() {
|
|||||||
|
|
||||||
// Signal chrome_elf to initialize crash reporting, rather than doing it in
|
// Signal chrome_elf to initialize crash reporting, rather than doing it in
|
||||||
// DllMain. See https://crbug.com/656800 for details.
|
// DllMain. See https://crbug.com/656800 for details.
|
||||||
void InitializeCrashReporting() {
|
void InitCrashReporter() {
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
if (initialized)
|
if (initialized)
|
||||||
return;
|
return;
|
||||||
@ -82,6 +86,47 @@ void InitializeCrashReporting() {
|
|||||||
}
|
}
|
||||||
#endif // defined(OS_WIN)
|
#endif // defined(OS_WIN)
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX) || defined(OS_WIN)
|
||||||
|
|
||||||
|
// Based on components/crash/content/app/run_as_crashpad_handler_win.cc
|
||||||
|
// Remove the "--type=crashpad-handler" command-line flag that will otherwise
|
||||||
|
// confuse the crashpad handler.
|
||||||
|
// Chrome uses an embedded crashpad handler on Windows only and imports this
|
||||||
|
// function via the existing "run_as_crashpad_handler" target defined in
|
||||||
|
// components/crash/content/app/BUILD.gn. CEF uses an embedded handler on both
|
||||||
|
// Windows and macOS so we define the function here instead of using the
|
||||||
|
// existing target (because we can't use that target on macOS).
|
||||||
|
int RunAsCrashpadHandler(const base::CommandLine& command_line) {
|
||||||
|
base::CommandLine::StringVector argv = command_line.argv();
|
||||||
|
const base::CommandLine::StringType process_type =
|
||||||
|
FILE_PATH_LITERAL("--type=");
|
||||||
|
argv.erase(std::remove_if(argv.begin(), argv.end(),
|
||||||
|
[&process_type](const base::CommandLine::StringType& str) {
|
||||||
|
return base::StartsWith(str, process_type,
|
||||||
|
base::CompareCase::SENSITIVE) ||
|
||||||
|
(!str.empty() && str[0] == L'/');
|
||||||
|
}),
|
||||||
|
argv.end());
|
||||||
|
|
||||||
|
std::unique_ptr<char* []> argv_as_utf8(new char*[argv.size() + 1]);
|
||||||
|
std::vector<std::string> storage;
|
||||||
|
storage.reserve(argv.size());
|
||||||
|
for (size_t i = 0; i < argv.size(); ++i) {
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
storage.push_back(base::UTF16ToUTF8(argv[i]));
|
||||||
|
#else
|
||||||
|
storage.push_back(argv[i]);
|
||||||
|
#endif
|
||||||
|
argv_as_utf8[i] = &storage[i][0];
|
||||||
|
}
|
||||||
|
argv_as_utf8[argv.size()] = nullptr;
|
||||||
|
argv.clear();
|
||||||
|
return crashpad::HandlerMain(static_cast<int>(storage.size()),
|
||||||
|
argv_as_utf8.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(OS_MACOSX) || defined(OS_WIN)
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int CefExecuteProcess(const CefMainArgs& args,
|
int CefExecuteProcess(const CefMainArgs& args,
|
||||||
@ -91,7 +136,7 @@ int CefExecuteProcess(const CefMainArgs& args,
|
|||||||
#if defined(ARCH_CPU_X86_64)
|
#if defined(ARCH_CPU_X86_64)
|
||||||
DisableFMA3();
|
DisableFMA3();
|
||||||
#endif
|
#endif
|
||||||
InitializeCrashReporting();
|
InitCrashReporter();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
|
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
|
||||||
@ -112,9 +157,9 @@ int CefExecuteProcess(const CefMainArgs& args,
|
|||||||
if (process_type.empty())
|
if (process_type.empty())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_MACOSX) || defined(OS_WIN)
|
||||||
if (process_type == crash_reporter::switches::kCrashpadHandler)
|
if (process_type == crash_reporter::switches::kCrashpadHandler)
|
||||||
return crash_reporter::RunAsCrashpadHandler(command_line);
|
return RunAsCrashpadHandler(command_line);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CefMainDelegate main_delegate(application);
|
CefMainDelegate main_delegate(application);
|
||||||
@ -150,7 +195,7 @@ bool CefInitialize(const CefMainArgs& args,
|
|||||||
#if defined(ARCH_CPU_X86_64)
|
#if defined(ARCH_CPU_X86_64)
|
||||||
DisableFMA3();
|
DisableFMA3();
|
||||||
#endif
|
#endif
|
||||||
InitializeCrashReporting();
|
InitCrashReporter();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Return true if the global context already exists.
|
// Return true if the global context already exists.
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "chrome/browser/browser_about_handler.h"
|
#include "chrome/browser/browser_about_handler.h"
|
||||||
#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
|
#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
|
||||||
#include "chrome/common/url_constants.h"
|
#include "chrome/common/url_constants.h"
|
||||||
|
#include "content/browser/frame_host/debug_urls.h"
|
||||||
#include "content/browser/webui/content_web_ui_controller_factory.h"
|
#include "content/browser/webui/content_web_ui_controller_factory.h"
|
||||||
#include "content/public/browser/browser_url_handler.h"
|
#include "content/public/browser/browser_url_handler.h"
|
||||||
#include "content/public/common/url_constants.h"
|
#include "content/public/common/url_constants.h"
|
||||||
@ -74,6 +75,13 @@ const char* kAllowedWebUIHosts[] = {
|
|||||||
content::kChromeUIWebRTCInternalsHost,
|
content::kChromeUIWebRTCInternalsHost,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Hosts that don't have useful output when linked directly. They'll be excluded
|
||||||
|
// from the "chrome://webui-hosts" listing.
|
||||||
|
const char* kUnlistedHosts[] = {
|
||||||
|
content::kChromeUINetworkErrorHost,
|
||||||
|
content::kChromeUIResourcesHost,
|
||||||
|
};
|
||||||
|
|
||||||
enum ChromeHostId {
|
enum ChromeHostId {
|
||||||
CHROME_UNKNOWN = 0,
|
CHROME_UNKNOWN = 0,
|
||||||
CHROME_LICENSE,
|
CHROME_LICENSE,
|
||||||
@ -103,18 +111,87 @@ ChromeHostId GetChromeHostId(const std::string& host) {
|
|||||||
return CHROME_UNKNOWN;
|
return CHROME_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns CEF and WebUI hosts. Does not include chrome debug hosts (for
|
||||||
|
// crashing, etc).
|
||||||
void GetAllowedHosts(std::vector<std::string>* hosts) {
|
void GetAllowedHosts(std::vector<std::string>* hosts) {
|
||||||
|
// Hosts implemented by CEF.
|
||||||
for (size_t i = 0;
|
for (size_t i = 0;
|
||||||
i < sizeof(kAllowedCefHosts) / sizeof(kAllowedCefHosts[0]); ++i) {
|
i < sizeof(kAllowedCefHosts) / sizeof(kAllowedCefHosts[0]); ++i) {
|
||||||
hosts->push_back(kAllowedCefHosts[i].host);
|
hosts->push_back(kAllowedCefHosts[i].host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicitly whitelisted WebUI hosts.
|
||||||
for (size_t i = 0;
|
for (size_t i = 0;
|
||||||
i < sizeof(kAllowedWebUIHosts) / sizeof(kAllowedWebUIHosts[0]); ++i) {
|
i < sizeof(kAllowedWebUIHosts) / sizeof(kAllowedWebUIHosts[0]); ++i) {
|
||||||
hosts->push_back(kAllowedWebUIHosts[i]);
|
hosts->push_back(kAllowedWebUIHosts[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if a host should not be listed on "chrome://webui-hosts".
|
||||||
|
bool IsUnlistedHost(const std::string& host) {
|
||||||
|
for (size_t i = 0;
|
||||||
|
i < sizeof(kUnlistedHosts) / sizeof(kUnlistedHosts[0]); ++i) {
|
||||||
|
if (host == kUnlistedHosts[i])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if a host is WebUI and should be allowed to load.
|
||||||
|
bool IsAllowedWebUIHost(const std::string& host) {
|
||||||
|
// Explicitly whitelisted WebUI hosts.
|
||||||
|
for (size_t i = 0;
|
||||||
|
i < sizeof(kAllowedWebUIHosts) / sizeof(kAllowedWebUIHosts[0]); ++i) {
|
||||||
|
if (base::EqualsCaseInsensitiveASCII(kAllowedWebUIHosts[i],
|
||||||
|
host.c_str())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional debug URLs that are not included in chrome::kChromeDebugURLs.
|
||||||
|
const char* kAllowedDebugURLs[] = {
|
||||||
|
content::kChromeUIBrowserCrashURL,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns true for debug URLs that receive special handling (for crashes, etc).
|
||||||
|
bool IsDebugURL(const GURL& url) {
|
||||||
|
// URLs handled by the renderer process in
|
||||||
|
// content/renderer/render_frame_impl.cc MaybeHandleDebugURL().
|
||||||
|
if (content::IsRendererDebugURL(url))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Also include URLs handled by the browser process in
|
||||||
|
// content/browser/frame_host/debug_urls.cc HandleDebugURL().
|
||||||
|
for (int i = 0; i < chrome::kNumberOfChromeDebugURLs; ++i) {
|
||||||
|
GURL host(chrome::kChromeDebugURLs[i]);
|
||||||
|
if (url.GetOrigin() == host.GetOrigin())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0;
|
||||||
|
i < sizeof(kAllowedDebugURLs) / sizeof(kAllowedDebugURLs[0]); ++i) {
|
||||||
|
GURL host(kAllowedDebugURLs[i]);
|
||||||
|
if (url.GetOrigin() == host.GetOrigin())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetDebugURLs(std::vector<std::string>* urls) {
|
||||||
|
for (int i = 0; i < chrome::kNumberOfChromeDebugURLs; ++i) {
|
||||||
|
urls->push_back(chrome::kChromeDebugURLs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0;
|
||||||
|
i < sizeof(kAllowedDebugURLs) / sizeof(kAllowedDebugURLs[0]); ++i) {
|
||||||
|
urls->push_back(kAllowedDebugURLs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Intercepts all WebUI calls and either blocks them or forwards them to the
|
// Intercepts all WebUI calls and either blocks them or forwards them to the
|
||||||
// Content or Chrome WebUI factory as appropriate.
|
// Content or Chrome WebUI factory as appropriate.
|
||||||
class CefWebUIControllerFactory : public content::WebUIControllerFactory {
|
class CefWebUIControllerFactory : public content::WebUIControllerFactory {
|
||||||
@ -124,13 +201,8 @@ class CefWebUIControllerFactory : public content::WebUIControllerFactory {
|
|||||||
if (!url.SchemeIs(content::kChromeUIScheme))
|
if (!url.SchemeIs(content::kChromeUIScheme))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (size_t i = 0;
|
if (IsAllowedWebUIHost(url.host()))
|
||||||
i < sizeof(kAllowedWebUIHosts) / sizeof(kAllowedWebUIHosts[0]); ++i) {
|
return true;
|
||||||
if (base::EqualsCaseInsensitiveASCII(kAllowedWebUIHosts[i],
|
|
||||||
url.host().c_str())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -534,16 +606,32 @@ class Delegate : public InternalHandlerDelegate {
|
|||||||
std::string html = "<html>\n<head><title>WebUI Hosts</title></head>\n"
|
std::string html = "<html>\n<head><title>WebUI Hosts</title></head>\n"
|
||||||
"<body bgcolor=\"white\"><h3>WebUI Hosts</h3>\n<ul>\n";
|
"<body bgcolor=\"white\"><h3>WebUI Hosts</h3>\n<ul>\n";
|
||||||
|
|
||||||
std::vector<std::string> hosts;
|
std::vector<std::string> list;
|
||||||
GetAllowedHosts(&hosts);
|
GetAllowedHosts(&list);
|
||||||
std::sort(hosts.begin(), hosts.end());
|
std::sort(list.begin(), list.end());
|
||||||
|
|
||||||
for (size_t i = 0U; i < hosts.size(); ++i) {
|
for (size_t i = 0U; i < list.size(); ++i) {
|
||||||
html += "<li><a href=\"chrome://" + hosts[i] + "\">chrome://" +
|
if (IsUnlistedHost(list[i]))
|
||||||
hosts[i] + "</a></li>\n";
|
continue;
|
||||||
|
|
||||||
|
html += "<li><a href=\"chrome://" + list[i] + "\">chrome://" +
|
||||||
|
list[i] + "</a></li>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
html += "</ul></body>\n</html>";
|
list.clear();
|
||||||
|
GetDebugURLs(&list);
|
||||||
|
std::sort(list.begin(), list.end());
|
||||||
|
|
||||||
|
html += "</ul>\n<h3>For Debug</h3>\n"
|
||||||
|
"<p>The following pages are for debugging purposes only. Because they "
|
||||||
|
"crash or hang the renderer, they're not linked directly; you can type "
|
||||||
|
"them into the address bar if you need them.</p>\n<ul>\n";
|
||||||
|
for (size_t i = 0U; i < list.size(); ++i) {
|
||||||
|
html += "<li>" + std::string(list[i]) + "</li>\n";
|
||||||
|
}
|
||||||
|
html += "</ul>\n";
|
||||||
|
|
||||||
|
html += "</body>\n</html>";
|
||||||
|
|
||||||
action->mime_type = "text/html";
|
action->mime_type = "text/html";
|
||||||
action->stream = CefStreamReader::CreateForData(
|
action->stream = CefStreamReader::CreateForData(
|
||||||
@ -604,6 +692,10 @@ class ChromeProtocolHandlerWrapper :
|
|||||||
net::URLRequestJob* MaybeCreateJob(
|
net::URLRequestJob* MaybeCreateJob(
|
||||||
net::URLRequest* request,
|
net::URLRequest* request,
|
||||||
net::NetworkDelegate* network_delegate) const override {
|
net::NetworkDelegate* network_delegate) const override {
|
||||||
|
// Don't handle debug URLs.
|
||||||
|
if (IsDebugURL(request->url()))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
// Only allow WebUI to handle chrome:// URLs whitelisted by CEF.
|
// Only allow WebUI to handle chrome:// URLs whitelisted by CEF.
|
||||||
if (CefWebUIControllerFactory::AllowWebUIForURL(request->url())) {
|
if (CefWebUIControllerFactory::AllowWebUIForURL(request->url())) {
|
||||||
return chrome_protocol_handler_->MaybeCreateJob(request,
|
return chrome_protocol_handler_->MaybeCreateJob(request,
|
||||||
|
247
libcef/common/cef_crash_report_upload_thread.cc
Normal file
247
libcef/common/cef_crash_report_upload_thread.cc
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
// Copyright 2016 The Chromium Embedded Framework 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 "libcef/common/cef_crash_report_upload_thread.h"
|
||||||
|
|
||||||
|
#include "third_party/crashpad/crashpad/client/settings.h"
|
||||||
|
|
||||||
|
using namespace crashpad;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Calls CrashReportDatabase::RecordUploadAttempt() with |successful| set to
|
||||||
|
// false upon destruction unless disarmed by calling Fire() or Disarm(). Fire()
|
||||||
|
// triggers an immediate call. Armed upon construction.
|
||||||
|
class CallRecordUploadAttempt {
|
||||||
|
public:
|
||||||
|
CallRecordUploadAttempt(CrashReportDatabase* database,
|
||||||
|
const CrashReportDatabase::Report* report)
|
||||||
|
: database_(database),
|
||||||
|
report_(report) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~CallRecordUploadAttempt() {
|
||||||
|
Fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fire() {
|
||||||
|
if (report_) {
|
||||||
|
database_->RecordUploadAttempt(report_, false, std::string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Disarm();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Disarm() {
|
||||||
|
report_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CrashReportDatabase* database_; // weak
|
||||||
|
const CrashReportDatabase::Report* report_; // weak
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(CallRecordUploadAttempt);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
CefCrashReportUploadThread::CefCrashReportUploadThread(
|
||||||
|
CrashReportDatabase* database,
|
||||||
|
const std::string& url,
|
||||||
|
bool rate_limit,
|
||||||
|
int max_uploads)
|
||||||
|
: CrashReportUploadThread(database, url, rate_limit),
|
||||||
|
max_uploads_(max_uploads) {
|
||||||
|
}
|
||||||
|
|
||||||
|
CefCrashReportUploadThread::~CefCrashReportUploadThread() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefCrashReportUploadThread::ProcessPendingReports() {
|
||||||
|
if (BackoffPending()) {
|
||||||
|
// Try again later.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaxUploadsEnabled()) {
|
||||||
|
// Retrieve all completed reports.
|
||||||
|
std::vector<CrashReportDatabase::Report> reports;
|
||||||
|
if (database_->GetCompletedReports(&reports) !=
|
||||||
|
CrashReportDatabase::kNoError) {
|
||||||
|
// The database is sick. It might be prudent to stop trying to poke it
|
||||||
|
// from this thread by abandoning the thread altogether. On the other
|
||||||
|
// hand, if the problem is transient, it might be possible to talk to it
|
||||||
|
// again on the next pass. For now, take the latter approach.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const time_t now = time(nullptr);
|
||||||
|
const int kSeconds = 60 * 60 * 24; // 24 hours
|
||||||
|
|
||||||
|
// Count how many reports have completed in the last 24 hours.
|
||||||
|
recent_upload_ct_ = 0;
|
||||||
|
for (const CrashReportDatabase::Report& report : reports) {
|
||||||
|
if (report.last_upload_attempt_time > now - kSeconds)
|
||||||
|
recent_upload_ct_++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue with processing pending reports.
|
||||||
|
CrashReportUploadThread::ProcessPendingReports();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefCrashReportUploadThread::ProcessPendingReport(
|
||||||
|
const CrashReportDatabase::Report& report) {
|
||||||
|
// Always allow upload if it's been explicitly requested by the user.
|
||||||
|
if (!report.upload_explicitly_requested) {
|
||||||
|
if (!UploadsEnabled()) {
|
||||||
|
// Don’t attempt an upload if there’s no URL or if uploads have been
|
||||||
|
// disabled in the database’s settings.
|
||||||
|
database_->SkipReportUpload(
|
||||||
|
report.uuid, Metrics::CrashSkippedReason::kUploadsDisabled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaxUploadsExceeded()) {
|
||||||
|
// Don't send uploads if the rate limit has been exceeded.
|
||||||
|
database_->SkipReportUpload(
|
||||||
|
report.uuid, Metrics::CrashSkippedReason::kUploadThrottled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BackoffPending()) {
|
||||||
|
// Try again later.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CrashReportDatabase::Report* upload_report;
|
||||||
|
CrashReportDatabase::OperationStatus status =
|
||||||
|
database_->GetReportForUploading(report.uuid, &upload_report);
|
||||||
|
switch (status) {
|
||||||
|
case CrashReportDatabase::kNoError:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CrashReportDatabase::kBusyError:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case CrashReportDatabase::kReportNotFound:
|
||||||
|
case CrashReportDatabase::kFileSystemError:
|
||||||
|
case CrashReportDatabase::kDatabaseError:
|
||||||
|
// In these cases, SkipReportUpload() might not work either, but it’s best
|
||||||
|
// to at least try to get the report out of the way.
|
||||||
|
database_->SkipReportUpload(report.uuid,
|
||||||
|
Metrics::CrashSkippedReason::kDatabaseError);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case CrashReportDatabase::kCannotRequestUpload:
|
||||||
|
NOTREACHED();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CallRecordUploadAttempt call_record_upload_attempt(database_, upload_report);
|
||||||
|
|
||||||
|
std::string response_body;
|
||||||
|
UploadResult upload_result = UploadReport(upload_report, &response_body);
|
||||||
|
switch (upload_result) {
|
||||||
|
case UploadResult::kSuccess:
|
||||||
|
// The upload completed successfully.
|
||||||
|
call_record_upload_attempt.Disarm();
|
||||||
|
database_->RecordUploadAttempt(upload_report, true, response_body);
|
||||||
|
if (MaxUploadsEnabled())
|
||||||
|
recent_upload_ct_++;
|
||||||
|
ResetBackoff();
|
||||||
|
break;
|
||||||
|
case UploadResult::kPermanentFailure:
|
||||||
|
// The upload should never be retried.
|
||||||
|
call_record_upload_attempt.Fire();
|
||||||
|
database_->SkipReportUpload(report.uuid,
|
||||||
|
Metrics::CrashSkippedReason::kUploadFailed);
|
||||||
|
break;
|
||||||
|
case UploadResult::kRetry:
|
||||||
|
// The upload will be retried after a reasonable backoff delay. Since we
|
||||||
|
// didn't successfully upload it we won't count it against the rate limit.
|
||||||
|
IncreaseBackoff();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefCrashReportUploadThread::UploadsEnabled() const {
|
||||||
|
Settings* const settings = database_->GetSettings();
|
||||||
|
bool uploads_enabled;
|
||||||
|
return !url_.empty() &&
|
||||||
|
settings->GetUploadsEnabled(&uploads_enabled) && uploads_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefCrashReportUploadThread::MaxUploadsEnabled() const {
|
||||||
|
return rate_limit_ && max_uploads_ > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefCrashReportUploadThread::MaxUploadsExceeded() const {
|
||||||
|
return MaxUploadsEnabled() && recent_upload_ct_ >= max_uploads_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefCrashReportUploadThread::BackoffPending() const {
|
||||||
|
if (!rate_limit_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Settings* const settings = database_->GetSettings();
|
||||||
|
|
||||||
|
time_t next_upload_time;
|
||||||
|
if (settings->GetNextUploadAttemptTime(&next_upload_time) &&
|
||||||
|
next_upload_time > 0) {
|
||||||
|
const time_t now = time(nullptr);
|
||||||
|
if (now < next_upload_time)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefCrashReportUploadThread::IncreaseBackoff() {
|
||||||
|
if (!rate_limit_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int kHour = 60 * 60; // 1 hour
|
||||||
|
const int kBackoffSchedule[] = {
|
||||||
|
kHour / 4, // 15 minutes
|
||||||
|
kHour, // 1 hour
|
||||||
|
kHour * 2, // 2 hours
|
||||||
|
kHour * 4, // 4 hours
|
||||||
|
kHour * 8, // 8 hours
|
||||||
|
kHour * 24, // 24 hours
|
||||||
|
};
|
||||||
|
const int kBackoffScheduleSize =
|
||||||
|
sizeof(kBackoffSchedule) / sizeof(kBackoffSchedule[0]);
|
||||||
|
|
||||||
|
Settings* settings = database_->GetSettings();
|
||||||
|
|
||||||
|
int backoff_step = 0;
|
||||||
|
if (settings->GetBackoffStep(&backoff_step) && backoff_step < 0)
|
||||||
|
backoff_step = 0;
|
||||||
|
if (++backoff_step > kBackoffScheduleSize)
|
||||||
|
backoff_step = kBackoffScheduleSize;
|
||||||
|
|
||||||
|
time_t next_upload_time = time(nullptr); // now
|
||||||
|
next_upload_time += kBackoffSchedule[backoff_step - 1];
|
||||||
|
|
||||||
|
settings->SetBackoffStep(backoff_step);
|
||||||
|
settings->SetNextUploadAttemptTime(next_upload_time);
|
||||||
|
|
||||||
|
if (max_uploads_ > 1) {
|
||||||
|
// If the server is having trouble then we don't want to send many crash
|
||||||
|
// reports after the backoff expires. Reduce max uploads to 1 per 24 hours
|
||||||
|
// until the client is restarted.
|
||||||
|
max_uploads_ = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefCrashReportUploadThread::ResetBackoff() {
|
||||||
|
if (!rate_limit_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Settings* settings = database_->GetSettings();
|
||||||
|
settings->SetBackoffStep(0);
|
||||||
|
settings->SetNextUploadAttemptTime(0);
|
||||||
|
}
|
42
libcef/common/cef_crash_report_upload_thread.h
Normal file
42
libcef/common/cef_crash_report_upload_thread.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef CEF_LIBCEF_COMMON_CEF_CRASH_REPORT_UPLOAD_THREAD_H_
|
||||||
|
#define CEF_LIBCEF_COMMON_CEF_CRASH_REPORT_UPLOAD_THREAD_H_
|
||||||
|
|
||||||
|
#include "third_party/crashpad/crashpad/handler/crash_report_upload_thread.h"
|
||||||
|
|
||||||
|
class CefCrashReportUploadThread : public crashpad::CrashReportUploadThread {
|
||||||
|
public:
|
||||||
|
CefCrashReportUploadThread(crashpad::CrashReportDatabase* database,
|
||||||
|
const std::string& url,
|
||||||
|
bool rate_limit,
|
||||||
|
int max_uploads);
|
||||||
|
~CefCrashReportUploadThread();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ProcessPendingReports() override;
|
||||||
|
void ProcessPendingReport(
|
||||||
|
const crashpad::CrashReportDatabase::Report& report) override;
|
||||||
|
|
||||||
|
bool UploadsEnabled() const;
|
||||||
|
|
||||||
|
bool MaxUploadsEnabled() const;
|
||||||
|
bool MaxUploadsExceeded() const;
|
||||||
|
|
||||||
|
bool BackoffPending() const;
|
||||||
|
void IncreaseBackoff();
|
||||||
|
void ResetBackoff();
|
||||||
|
|
||||||
|
int max_uploads_;
|
||||||
|
|
||||||
|
// Track the number of uploads that have completed within the last 24 hours.
|
||||||
|
// Only used when RateLimitEnabled() is true. Value is reset each time
|
||||||
|
// ProcessPendingReports() is called.
|
||||||
|
int recent_upload_ct_ = 0;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(CefCrashReportUploadThread);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CEF_LIBCEF_COMMON_CEF_CRASH_REPORT_UPLOAD_THREAD_H_
|
@ -82,9 +82,6 @@ const char kEnableSpeechInput[] = "enable-speech-input";
|
|||||||
// Enable the speech input profanity filter.
|
// Enable the speech input profanity filter.
|
||||||
const char kEnableProfanityFilter[] = "enable-profanity-filter";
|
const char kEnableProfanityFilter[] = "enable-profanity-filter";
|
||||||
|
|
||||||
// The directory breakpad should store minidumps in.
|
|
||||||
const char kCrashDumpsDir[] = "crash-dumps-dir";
|
|
||||||
|
|
||||||
// Disable spell checking.
|
// Disable spell checking.
|
||||||
const char kDisableSpellChecking[] = "disable-spell-checking";
|
const char kDisableSpellChecking[] = "disable-spell-checking";
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ extern const char kPersistUserPreferences[];
|
|||||||
extern const char kEnableMediaStream[];
|
extern const char kEnableMediaStream[];
|
||||||
extern const char kEnableSpeechInput[];
|
extern const char kEnableSpeechInput[];
|
||||||
extern const char kEnableProfanityFilter[];
|
extern const char kEnableProfanityFilter[];
|
||||||
extern const char kCrashDumpsDir[];
|
|
||||||
extern const char kDisableSpellChecking[];
|
extern const char kDisableSpellChecking[];
|
||||||
extern const char kEnableSpellingService[];
|
extern const char kEnableSpellingService[];
|
||||||
extern const char kOverrideSpellCheckLang[];
|
extern const char kOverrideSpellCheckLang[];
|
||||||
|
@ -1,26 +1,465 @@
|
|||||||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// 2016 The Chromium Authors. All rights reserved. Use of this source code is
|
||||||
// found in the LICENSE file.
|
// governed by a BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
#include "libcef/common/crash_reporter_client.h"
|
#include "libcef/common/crash_reporter_client.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "libcef/common/cef_switches.h"
|
#if defined(OS_WIN)
|
||||||
#include "include/cef_version.h"
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "base/command_line.h"
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/files/file_path.h"
|
|
||||||
#include "base/strings/string16.h"
|
#include "base/strings/string16.h"
|
||||||
#include "base/strings/stringprintf.h"
|
#include "base/strings/stringprintf.h"
|
||||||
|
#include "base/strings/string_number_conversions.h"
|
||||||
|
#include "base/strings/string_split.h"
|
||||||
|
#include "base/strings/string_util.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
|
#include "chrome/common/crash_keys.h"
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX)
|
||||||
|
#include "base/mac/foundation_util.h"
|
||||||
|
#else
|
||||||
|
#include "include/cef_version.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_POSIX)
|
||||||
|
// Don't use CommandLine, FilePath or PathService on Windows. FilePath has
|
||||||
|
// dependencies outside of kernel32, which is disallowed by chrome_elf.
|
||||||
|
// CommandLine and PathService depend on global state that will not be
|
||||||
|
// initialized at the time the CefCrashReporterClient object is created.
|
||||||
|
#include "base/command_line.h"
|
||||||
|
#include "base/environment.h"
|
||||||
|
#include "base/files/file_path.h"
|
||||||
|
#include "base/path_service.h"
|
||||||
|
#include "chrome/common/chrome_paths.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
||||||
#include "content/public/common/content_switches.h"
|
#include "content/public/common/content_switches.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
#include "base/debug/leak_annotations.h"
|
||||||
|
#include "chrome/install_static/install_util.h"
|
||||||
|
#include "components/crash/content/app/crashpad.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
typedef base::string16 PathString;
|
||||||
|
const char kPathSep = '\\';
|
||||||
|
#else
|
||||||
|
typedef std::string PathString;
|
||||||
|
const char kPathSep = '/';
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PathString GetCrashConfigPath() {
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
// Start with the path to the running executable.
|
||||||
|
wchar_t module_path[MAX_PATH];
|
||||||
|
if (GetModuleFileName(nullptr, module_path, MAX_PATH) == 0)
|
||||||
|
return PathString();
|
||||||
|
|
||||||
|
PathString config_path = module_path;
|
||||||
|
|
||||||
|
// Remove the executable file name.
|
||||||
|
PathString::size_type last_backslash =
|
||||||
|
config_path.rfind(kPathSep, config_path.size());
|
||||||
|
if (last_backslash != PathString::npos)
|
||||||
|
config_path.erase(last_backslash + 1);
|
||||||
|
|
||||||
|
config_path += L"crash_reporter.cfg";
|
||||||
|
return config_path;
|
||||||
|
#elif defined(OS_POSIX)
|
||||||
|
// Start with the path to the running executable.
|
||||||
|
base::FilePath config_path;
|
||||||
|
if (!PathService::Get(base::DIR_EXE, &config_path))
|
||||||
|
return PathString();
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX)
|
||||||
|
// Get the main app bundle path.
|
||||||
|
config_path = base::mac::GetAppBundlePath(config_path);
|
||||||
|
if (config_path.empty())
|
||||||
|
return PathString();
|
||||||
|
|
||||||
|
// Go into the Contents/Resources directory.
|
||||||
|
config_path = config_path.Append(FILE_PATH_LITERAL("Contents"))
|
||||||
|
.Append(FILE_PATH_LITERAL("Resources"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return config_path.Append(FILE_PATH_LITERAL("crash_reporter.cfg")).value();
|
||||||
|
#endif // defined(OS_POSIX)
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Windows, FAT32 and NTFS both limit filenames to a maximum of 255
|
||||||
|
// characters. On POSIX systems, the typical filename length limit is 255
|
||||||
|
// character units. HFS+'s limit is actually 255 Unicode characters using
|
||||||
|
// Apple's modification of Normalization Form D, but the differences aren't
|
||||||
|
// really worth dealing with here.
|
||||||
|
const unsigned maxFilenameLength = 255;
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
|
||||||
|
const char kInvalidFileChars[] = "<>:\"/\\|?*";
|
||||||
|
|
||||||
|
bool isInvalidFileCharacter(unsigned char c) {
|
||||||
|
if (c < ' ' || c == 0x7F)
|
||||||
|
return true;
|
||||||
|
for(size_t i = 0; i < sizeof(kInvalidFileChars); ++i) {
|
||||||
|
if (c == kInvalidFileChars[i])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAbsolutePath(const std::string& s) {
|
||||||
|
// Check for local paths (beginning with "c:\") and network paths
|
||||||
|
// (beginning with "\\").
|
||||||
|
return s.length() > 2 &&
|
||||||
|
((isalpha(s[0]) && s[1] == ':' && s[2] == kPathSep) ||
|
||||||
|
(s[0] == kPathSep && s[1] == kPathSep));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string extractAbsolutePathStart(std::string& s) {
|
||||||
|
if (!isAbsolutePath(s))
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::string start;
|
||||||
|
if (s[0] == kPathSep) {
|
||||||
|
// Network path.
|
||||||
|
start = s.substr(0, 2);
|
||||||
|
s = s.substr(2);
|
||||||
|
} else {
|
||||||
|
// Local path.
|
||||||
|
start = s.substr(0, 3);
|
||||||
|
s = s.substr(3);
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(OS_POSIX)
|
||||||
|
|
||||||
|
bool isInvalidFileCharacter(unsigned char c) {
|
||||||
|
// HFS+ disallows '/' and Linux systems also disallow null. For sanity's sake
|
||||||
|
// we'll also disallow control characters.
|
||||||
|
return c < ' ' || c == 0x7F || c == kPathSep;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAbsolutePath(const std::string& s) {
|
||||||
|
// Check for local paths (beginning with "/") and network paths (beginning
|
||||||
|
// with "//").
|
||||||
|
return s.length() > 1 && s[0] == kPathSep;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string extractAbsolutePathStart(std::string& s) {
|
||||||
|
if (!isAbsolutePath(s))
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
// May have multiple '/' at the beginning of the path.
|
||||||
|
std::string start;
|
||||||
|
do {
|
||||||
|
s = s.substr(1);
|
||||||
|
start.push_back(kPathSep);
|
||||||
|
} while (s.length() > 0 && s[0] == kPathSep);
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(OS_POSIX)
|
||||||
|
|
||||||
|
std::string sanitizePathComponentPart(const std::string& s) {
|
||||||
|
if (s.empty())
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
result.reserve(s.length());
|
||||||
|
std::remove_copy_if(s.begin(), s.end(),
|
||||||
|
std::back_inserter(result),
|
||||||
|
std::not1(std::ptr_fun(isInvalidFileCharacter)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sanitizePathComponent(const std::string& s) {
|
||||||
|
std::string name, ext;
|
||||||
|
|
||||||
|
// Separate name and extension, if any.
|
||||||
|
std::string::size_type pos = s.rfind('.');
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
name = s.substr(0, pos);
|
||||||
|
ext = s.substr(pos + 1);
|
||||||
|
} else {
|
||||||
|
name = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove invalid characters.
|
||||||
|
name = sanitizePathComponentPart(name);
|
||||||
|
ext = sanitizePathComponentPart(ext);
|
||||||
|
|
||||||
|
// Remove a ridiculously-long extension.
|
||||||
|
if (ext.length() >= maxFilenameLength)
|
||||||
|
ext = std::string();
|
||||||
|
|
||||||
|
// Truncate an overly-long filename, reserving one character for a dot.
|
||||||
|
std::string::size_type max_name_len = maxFilenameLength - ext.length() - 1;
|
||||||
|
if (name.length() > max_name_len)
|
||||||
|
name = name.substr(0, max_name_len);
|
||||||
|
|
||||||
|
return ext.empty() ? name : name + "." + ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sanitizePath(const std::string& s) {
|
||||||
|
std::string path = s;
|
||||||
|
|
||||||
|
// Extract the absolute path start component, if any (e.g. "c:\" on Windows).
|
||||||
|
std::string result = extractAbsolutePathStart(path);
|
||||||
|
result.reserve(s.length());
|
||||||
|
|
||||||
|
std::vector<std::string> parts =
|
||||||
|
base::SplitString(path, std::string() + kPathSep, base::KEEP_WHITESPACE,
|
||||||
|
base::SPLIT_WANT_NONEMPTY);
|
||||||
|
for (size_t i = 0; i < parts.size(); ++i) {
|
||||||
|
std::string part = parts[i];
|
||||||
|
if (part != "." && part != "..")
|
||||||
|
part = sanitizePathComponent(part);
|
||||||
|
if (!result.empty() && result[result.length()-1] != kPathSep)
|
||||||
|
result += kPathSep;
|
||||||
|
result += part;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string joinPath(const std::string& s1, const std::string& s2) {
|
||||||
|
if (s1.empty() && s2.empty())
|
||||||
|
return std::string();
|
||||||
|
if (s1.empty())
|
||||||
|
return s2;
|
||||||
|
if (s2.empty())
|
||||||
|
return s1;
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
// Don't try to join absolute paths on Windows.
|
||||||
|
// Skip this check on POSIX where it's more difficult to differentiate.
|
||||||
|
if (isAbsolutePath(s2))
|
||||||
|
return s2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string result = s1;
|
||||||
|
if (result[result.size() - 1] != kPathSep)
|
||||||
|
result += kPathSep;
|
||||||
|
if (s2[0] == kPathSep)
|
||||||
|
result += s2.substr(1);
|
||||||
|
else
|
||||||
|
result += s2;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
// This will only be non-nullptr in the chrome_elf address space.
|
||||||
|
CefCrashReporterClient* g_crash_reporter_client = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// Export functions from chrome_elf that are required by
|
||||||
|
// crash_reporting_win::InitializeCrashReportingForModule().
|
||||||
|
|
||||||
|
size_t __declspec(dllexport) __cdecl GetCrashKeyCountImpl() {
|
||||||
|
if (!g_crash_reporter_client)
|
||||||
|
return 0;
|
||||||
|
return g_crash_reporter_client->GetCrashKeyCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __declspec(dllexport) __cdecl GetCrashKeyImpl(size_t index,
|
||||||
|
const char** key_name,
|
||||||
|
size_t* max_length) {
|
||||||
|
if (!g_crash_reporter_client)
|
||||||
|
return false;
|
||||||
|
return g_crash_reporter_client->GetCrashKey(index, key_name, max_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
#endif // OS_WIN
|
||||||
|
|
||||||
CefCrashReporterClient::CefCrashReporterClient() {}
|
CefCrashReporterClient::CefCrashReporterClient() {}
|
||||||
CefCrashReporterClient::~CefCrashReporterClient() {}
|
CefCrashReporterClient::~CefCrashReporterClient() {}
|
||||||
|
|
||||||
|
// Be aware that logging is not initialized at the time this method is called.
|
||||||
|
bool CefCrashReporterClient::ReadCrashConfigFile() {
|
||||||
|
if (has_crash_config_file_)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
PathString config_path = GetCrashConfigPath();
|
||||||
|
if (config_path.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
|
FILE* fp = _wfopen(config_path.c_str(), L"r");
|
||||||
|
#else
|
||||||
|
FILE* fp = fopen(config_path.c_str(), "r");
|
||||||
|
#endif
|
||||||
|
if (!fp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char line[1000];
|
||||||
|
|
||||||
|
enum section {
|
||||||
|
kNoSection,
|
||||||
|
kConfigSection,
|
||||||
|
kCrashKeysSection,
|
||||||
|
} current_section = kNoSection;
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line) - 1, fp) != NULL) {
|
||||||
|
std::string str = line;
|
||||||
|
base::TrimString(str, base::kWhitespaceASCII, &str);
|
||||||
|
if (str.empty() || str[0] == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (str == "[Config]") {
|
||||||
|
current_section = kConfigSection;
|
||||||
|
continue;
|
||||||
|
} else if (str == "[CrashKeys]") {
|
||||||
|
current_section = kCrashKeysSection;
|
||||||
|
continue;
|
||||||
|
} else if (str[0] == '[') {
|
||||||
|
current_section = kNoSection;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_section == kNoSection)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
size_t div = str.find('=');
|
||||||
|
if (div == std::string::npos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string name_str = str.substr(0, div);
|
||||||
|
base::TrimString(name_str, base::kWhitespaceASCII, &name_str);
|
||||||
|
std::string val_str = str.substr(div + 1);
|
||||||
|
base::TrimString(val_str, base::kWhitespaceASCII, &val_str);
|
||||||
|
if (name_str.empty() || val_str.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (current_section == kConfigSection) {
|
||||||
|
if (name_str == "ServerURL") {
|
||||||
|
if (val_str.find("http://") == 0 || val_str.find("https://") == 0)
|
||||||
|
server_url_ = val_str;
|
||||||
|
} else if (name_str == "RateLimitEnabled") {
|
||||||
|
rate_limit_ = (base::EqualsCaseInsensitiveASCII(val_str, "true") ||
|
||||||
|
val_str == "1");
|
||||||
|
} else if (name_str == "MaxUploadsPerDay") {
|
||||||
|
if (base::StringToInt(val_str, &max_uploads_)) {
|
||||||
|
if (max_uploads_ < 0)
|
||||||
|
max_uploads_ = 0;
|
||||||
|
}
|
||||||
|
} else if (name_str == "MaxDatabaseSizeInMb") {
|
||||||
|
if (base::StringToInt(val_str, &max_db_size_)) {
|
||||||
|
if (max_db_size_ < 0)
|
||||||
|
max_db_size_ = 0;
|
||||||
|
}
|
||||||
|
} else if (name_str == "MaxDatabaseAgeInDays") {
|
||||||
|
if (base::StringToInt(val_str, &max_db_age_)) {
|
||||||
|
if (max_db_age_ < 0)
|
||||||
|
max_db_age_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
else if (name_str == "ExternalHandler") {
|
||||||
|
external_handler_ = sanitizePath(name_str);
|
||||||
|
} else if (name_str == "AppName") {
|
||||||
|
app_name_ = sanitizePathComponent(val_str);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (current_section == kCrashKeysSection) {
|
||||||
|
size_t max_size = 0;
|
||||||
|
if (val_str == "small")
|
||||||
|
max_size = crash_keys::kSmallSize;
|
||||||
|
else if (val_str == "medium")
|
||||||
|
max_size = crash_keys::kMediumSize;
|
||||||
|
else if (val_str == "large")
|
||||||
|
max_size = crash_keys::kLargeSize;
|
||||||
|
|
||||||
|
if (max_size == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
crash_keys_.push_back({name_str, max_size});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
// Add the list of potential crash keys from chrome, content and other layers.
|
||||||
|
// Do it here so that they're also exported to the libcef module for Windows.
|
||||||
|
{
|
||||||
|
std::vector<base::debug::CrashKey> keys;
|
||||||
|
crash_keys::GetChromeCrashKeys(keys);
|
||||||
|
|
||||||
|
if (!keys.empty()) {
|
||||||
|
crash_keys_.reserve(crash_keys_.size() + keys.size());
|
||||||
|
for (const auto& key : keys) {
|
||||||
|
crash_keys_.push_back({key.key_name, key.max_length});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
has_crash_config_file_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefCrashReporterClient::HasCrashConfigFile() const {
|
||||||
|
return has_crash_config_file_;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
|
||||||
|
// static
|
||||||
|
void CefCrashReporterClient::InitializeCrashReportingForProcess() {
|
||||||
|
if (g_crash_reporter_client)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_crash_reporter_client = new CefCrashReporterClient();
|
||||||
|
ANNOTATE_LEAKING_OBJECT_PTR(g_crash_reporter_client);
|
||||||
|
|
||||||
|
if (!g_crash_reporter_client->ReadCrashConfigFile())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string process_type = install_static::GetSwitchValueFromCommandLine(
|
||||||
|
::GetCommandLineA(), install_static::kProcessType);
|
||||||
|
if (process_type != install_static::kCrashpadHandler) {
|
||||||
|
crash_reporter::SetCrashReporterClient(g_crash_reporter_client);
|
||||||
|
|
||||||
|
// If |embedded_handler| is true then we launch another instance of the main
|
||||||
|
// executable as the crashpad-handler process.
|
||||||
|
const bool embedded_handler =
|
||||||
|
!g_crash_reporter_client->HasCrashExternalHandler();
|
||||||
|
if (embedded_handler) {
|
||||||
|
crash_reporter::InitializeCrashpadWithEmbeddedHandler(
|
||||||
|
process_type.empty(), process_type);
|
||||||
|
} else {
|
||||||
|
crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefCrashReporterClient::GetAlternativeCrashDumpLocation(
|
||||||
|
base::string16* crash_dir) {
|
||||||
|
// By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
|
||||||
|
// location to write breakpad crash dumps can be set.
|
||||||
|
*crash_dir =
|
||||||
|
install_static::GetEnvironmentString16(L"BREAKPAD_DUMP_LOCATION");
|
||||||
|
return !crash_dir->empty();
|
||||||
|
}
|
||||||
|
|
||||||
void CefCrashReporterClient::GetProductNameAndVersion(
|
void CefCrashReporterClient::GetProductNameAndVersion(
|
||||||
const base::string16& exe_path,
|
const base::string16& exe_path,
|
||||||
base::string16* product_name,
|
base::string16* product_name,
|
||||||
@ -32,9 +471,27 @@ void CefCrashReporterClient::GetProductNameAndVersion(
|
|||||||
*special_build = base::string16();
|
*special_build = base::string16();
|
||||||
*channel_name = base::string16();
|
*channel_name = base::string16();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS)
|
bool CefCrashReporterClient::GetCrashDumpLocation(base::string16* crash_dir) {
|
||||||
|
// By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
|
||||||
|
// location to write breakpad crash dumps can be set.
|
||||||
|
if (GetAlternativeCrashDumpLocation(crash_dir))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return install_static::GetDefaultCrashDumpLocation(
|
||||||
|
crash_dir, base::UTF8ToUTF16(app_name_));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefCrashReporterClient::GetCrashMetricsLocation(
|
||||||
|
base::string16* metrics_dir) {
|
||||||
|
return install_static::GetDefaultUserDataDirectory(
|
||||||
|
metrics_dir, base::UTF8ToUTF16(app_name_));
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(OS_POSIX)
|
||||||
|
|
||||||
|
#if !defined(OS_MACOSX)
|
||||||
|
|
||||||
void CefCrashReporterClient::GetProductNameAndVersion(
|
void CefCrashReporterClient::GetProductNameAndVersion(
|
||||||
const char** product_name,
|
const char** product_name,
|
||||||
const char** version) {
|
const char** version) {
|
||||||
@ -45,27 +502,6 @@ void CefCrashReporterClient::GetProductNameAndVersion(
|
|||||||
base::FilePath CefCrashReporterClient::GetReporterLogFilename() {
|
base::FilePath CefCrashReporterClient::GetReporterLogFilename() {
|
||||||
return base::FilePath(FILE_PATH_LITERAL("uploads.log"));
|
return base::FilePath(FILE_PATH_LITERAL("uploads.log"));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
bool CefCrashReporterClient::GetCrashDumpLocation(base::string16* crash_dir) {
|
|
||||||
#else
|
|
||||||
bool CefCrashReporterClient::GetCrashDumpLocation(base::FilePath* crash_dir) {
|
|
||||||
#endif
|
|
||||||
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
||||||
switches::kCrashDumpsDir))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
base::FilePath crash_directory =
|
|
||||||
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
|
|
||||||
switches::kCrashDumpsDir);
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
*crash_dir = crash_directory.value();
|
|
||||||
#else
|
|
||||||
*crash_dir = std::move(crash_directory);
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CefCrashReporterClient::EnableBreakpadForProcess(
|
bool CefCrashReporterClient::EnableBreakpadForProcess(
|
||||||
const std::string& process_type) {
|
const std::string& process_type) {
|
||||||
@ -74,3 +510,121 @@ bool CefCrashReporterClient::EnableBreakpadForProcess(
|
|||||||
process_type == switches::kZygoteProcess ||
|
process_type == switches::kZygoteProcess ||
|
||||||
process_type == switches::kGpuProcess;
|
process_type == switches::kGpuProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !defined(OS_MACOSX)
|
||||||
|
|
||||||
|
bool CefCrashReporterClient::GetCrashDumpLocation(base::FilePath* crash_dir) {
|
||||||
|
// By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
|
||||||
|
// location to write breakpad crash dumps can be set.
|
||||||
|
std::unique_ptr<base::Environment> env(base::Environment::Create());
|
||||||
|
std::string alternate_crash_dump_location;
|
||||||
|
if (env->GetVar("BREAKPAD_DUMP_LOCATION", &alternate_crash_dump_location)) {
|
||||||
|
base::FilePath crash_dumps_dir_path =
|
||||||
|
base::FilePath::FromUTF8Unsafe(alternate_crash_dump_location);
|
||||||
|
PathService::Override(chrome::DIR_CRASH_DUMPS, crash_dumps_dir_path);
|
||||||
|
}
|
||||||
|
return PathService::Get(chrome::DIR_CRASH_DUMPS, crash_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !defined(OS_POSIX)
|
||||||
|
|
||||||
|
bool CefCrashReporterClient::GetCollectStatsConsent() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefCrashReporterClient::GetCollectStatsInSample() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(OS_WIN) || defined(OS_MACOSX)
|
||||||
|
bool CefCrashReporterClient::ReportingIsEnforcedByPolicy(
|
||||||
|
bool* crashpad_enabled) {
|
||||||
|
*crashpad_enabled = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t CefCrashReporterClient::RegisterCrashKeys() {
|
||||||
|
std::vector<base::debug::CrashKey> keys;
|
||||||
|
|
||||||
|
if (!crash_keys_.empty()) {
|
||||||
|
keys.reserve(crash_keys_.size());
|
||||||
|
for (const auto& key : crash_keys_) {
|
||||||
|
keys.push_back({key.key_name_.c_str(), key.max_length_});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base::debug::InitCrashKeys(&keys[0], keys.size(),
|
||||||
|
crash_keys::kChunkMaxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
||||||
|
bool CefCrashReporterClient::IsRunningUnattended() {
|
||||||
|
// Crash upload will only be enabled with Breakpad on Linux if this method
|
||||||
|
// returns false.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
size_t CefCrashReporterClient::GetCrashKeyCount() const {
|
||||||
|
return crash_keys_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefCrashReporterClient::GetCrashKey(size_t index,
|
||||||
|
const char** key_name,
|
||||||
|
size_t* max_length) const {
|
||||||
|
if (index >= crash_keys_.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto& key = crash_keys_[index];
|
||||||
|
*key_name = key.key_name_.c_str();
|
||||||
|
*max_length = key.max_length_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif // defined(OS_WIN)
|
||||||
|
|
||||||
|
std::string CefCrashReporterClient::GetCrashServerURL() {
|
||||||
|
return server_url_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See HandlerMain() in third_party/crashpad/crashpad/handler/handler_main.cc
|
||||||
|
// for supported arguments.
|
||||||
|
void CefCrashReporterClient::GetCrashOptionalArguments(
|
||||||
|
std::vector<std::string>* arguments) {
|
||||||
|
if (!rate_limit_)
|
||||||
|
arguments->push_back(std::string("--no-rate-limit"));
|
||||||
|
|
||||||
|
if (max_uploads_ > 0) {
|
||||||
|
arguments->push_back(
|
||||||
|
std::string("--max-uploads=") + base::IntToString(max_uploads_));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_db_size_ > 0) {
|
||||||
|
arguments->push_back(
|
||||||
|
std::string("--max-db-size=") + base::IntToString(max_db_size_));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_db_age_ > 0) {
|
||||||
|
arguments->push_back(
|
||||||
|
std::string("--max-db-age=") + base::IntToString(max_db_age_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
|
||||||
|
base::string16 CefCrashReporterClient::GetCrashExternalHandler(
|
||||||
|
const base::string16& exe_dir) {
|
||||||
|
if (external_handler_.empty())
|
||||||
|
return CrashReporterClient::GetCrashExternalHandler(exe_dir);
|
||||||
|
if (isAbsolutePath(external_handler_))
|
||||||
|
return base::UTF8ToUTF16(external_handler_);
|
||||||
|
return base::UTF8ToWide(
|
||||||
|
joinPath(base::UTF16ToUTF8(exe_dir), external_handler_));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefCrashReporterClient::HasCrashExternalHandler() const {
|
||||||
|
return !external_handler_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(OS_WIN)
|
||||||
|
@ -1,49 +1,109 @@
|
|||||||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// 2016 The Chromium Authors. All rights reserved. Use of this source code is
|
||||||
// found in the LICENSE file.
|
// governed by a BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
#ifndef CEF_LIBCEF_COMMON_CRASH_REPORTER_CLIENT_H_
|
#ifndef CEF_LIBCEF_COMMON_CRASH_REPORTER_CLIENT_H_
|
||||||
#define CEF_LIBCEF_COMMON_CRASH_REPORTER_CLIENT_H_
|
#define CEF_LIBCEF_COMMON_CRASH_REPORTER_CLIENT_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#include "components/crash/content/app/crash_reporter_client.h"
|
#include "components/crash/content/app/crash_reporter_client.h"
|
||||||
|
|
||||||
|
// Global object that is instantiated in each process and configures crash
|
||||||
|
// reporting. On Windows this is created by the
|
||||||
|
// InitializeCrashReportingForProcess() method called from chrome_elf. On
|
||||||
|
// Linux and macOS this is created by crash_reporting::BasicStartupComplete().
|
||||||
class CefCrashReporterClient : public crash_reporter::CrashReporterClient {
|
class CefCrashReporterClient : public crash_reporter::CrashReporterClient {
|
||||||
public:
|
public:
|
||||||
CefCrashReporterClient();
|
CefCrashReporterClient();
|
||||||
~CefCrashReporterClient() override;
|
~CefCrashReporterClient() override;
|
||||||
|
|
||||||
|
// Reads the crash config file and returns true on success. Failure to read
|
||||||
|
// the crash config file will disable crash reporting. This method should be
|
||||||
|
// called immediately after the CefCrashReporterClient instance is created.
|
||||||
|
bool ReadCrashConfigFile();
|
||||||
|
bool HasCrashConfigFile() const;
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
// Returns a textual description of the product type and version to include
|
// Called from chrome_elf (chrome_elf/crash/crash_helper.cc) to instantiate
|
||||||
// in the crash report.
|
// a process wide instance of CefCrashReporterClient and initialize crash
|
||||||
|
// reporting for the process. The instance is leaked.
|
||||||
|
// crash_reporting_win::InitializeCrashReportingForModule() will be called
|
||||||
|
// later from crash_reporting::PreSandboxStartup() to read global state into
|
||||||
|
// the module address space.
|
||||||
|
static void InitializeCrashReportingForProcess();
|
||||||
|
|
||||||
|
bool GetAlternativeCrashDumpLocation(base::string16* crash_dir) override;
|
||||||
void GetProductNameAndVersion(const base::string16& exe_path,
|
void GetProductNameAndVersion(const base::string16& exe_path,
|
||||||
base::string16* product_name,
|
base::string16* product_name,
|
||||||
base::string16* version,
|
base::string16* version,
|
||||||
base::string16* special_build,
|
base::string16* special_build,
|
||||||
base::string16* channel_name) override;
|
base::string16* channel_name) override;
|
||||||
#endif
|
bool GetCrashDumpLocation(base::string16* crash_dir) override;
|
||||||
|
bool GetCrashMetricsLocation(base::string16* metrics_dir) override;
|
||||||
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS)
|
#elif defined(OS_POSIX)
|
||||||
// Returns a textual description of the product type and version to include
|
#if !defined(OS_MACOSX)
|
||||||
// in the crash report.
|
|
||||||
void GetProductNameAndVersion(const char** product_name,
|
void GetProductNameAndVersion(const char** product_name,
|
||||||
const char** version) override;
|
const char** version) override;
|
||||||
|
|
||||||
base::FilePath GetReporterLogFilename() override;
|
base::FilePath GetReporterLogFilename() override;
|
||||||
#endif
|
|
||||||
|
|
||||||
// The location where minidump files should be written. Returns true if
|
|
||||||
// |crash_dir| was set.
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
bool GetCrashDumpLocation(base::string16* crash_dir) override;
|
|
||||||
#else
|
|
||||||
bool GetCrashDumpLocation(base::FilePath* crash_dir) override;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool EnableBreakpadForProcess(const std::string& process_type) override;
|
bool EnableBreakpadForProcess(const std::string& process_type) override;
|
||||||
|
#endif
|
||||||
|
bool GetCrashDumpLocation(base::FilePath* crash_dir) override;
|
||||||
|
#endif // defined(OS_POSIX)
|
||||||
|
|
||||||
|
// All of these methods must return true to enable crash report upload.
|
||||||
|
bool GetCollectStatsConsent() override;
|
||||||
|
bool GetCollectStatsInSample() override;
|
||||||
|
#if defined(OS_WIN) || defined(OS_MACOSX)
|
||||||
|
bool ReportingIsEnforcedByPolicy(bool* crashpad_enabled) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t RegisterCrashKeys() override;
|
||||||
|
|
||||||
|
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
||||||
|
bool IsRunningUnattended() override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
size_t GetCrashKeyCount() const;
|
||||||
|
bool GetCrashKey(size_t index,
|
||||||
|
const char** key_name,
|
||||||
|
size_t* max_length) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string GetCrashServerURL() override;
|
||||||
|
void GetCrashOptionalArguments(std::vector<std::string>* arguments) override;
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
base::string16 GetCrashExternalHandler(
|
||||||
|
const base::string16& exe_dir) override;
|
||||||
|
bool HasCrashExternalHandler() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool has_crash_config_file_ = false;
|
||||||
|
|
||||||
|
// Values that will persist until the end of the program.
|
||||||
|
// Matches the members of base::debug::CrashKey.
|
||||||
|
struct StoredCrashKey {
|
||||||
|
std::string key_name_;
|
||||||
|
size_t max_length_;
|
||||||
|
};
|
||||||
|
std::vector<StoredCrashKey> crash_keys_;
|
||||||
|
std::string server_url_;
|
||||||
|
bool rate_limit_ = true;
|
||||||
|
int max_uploads_ = 5;
|
||||||
|
int max_db_size_ = 20;
|
||||||
|
int max_db_age_ = 5;
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
std::string app_name_ = "CEF";
|
||||||
|
std::string external_handler_;
|
||||||
|
#endif
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(CefCrashReporterClient);
|
DISALLOW_COPY_AND_ASSIGN(CefCrashReporterClient);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
190
libcef/common/crash_reporting.cc
Normal file
190
libcef/common/crash_reporting.cc
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
|
||||||
|
// 2016 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 "libcef/common/crash_reporting.h"
|
||||||
|
|
||||||
|
#include "include/cef_crash_util.h"
|
||||||
|
#include "libcef/common/cef_switches.h"
|
||||||
|
|
||||||
|
#include "base/base_switches.h"
|
||||||
|
#include "base/command_line.h"
|
||||||
|
#include "base/debug/crash_logging.h"
|
||||||
|
#include "base/strings/string_util.h"
|
||||||
|
#include "chrome/common/crash_keys.h"
|
||||||
|
#include "content/public/common/content_switches.h"
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX)
|
||||||
|
#include "base/mac/foundation_util.h"
|
||||||
|
#include "components/crash/content/app/crashpad.h"
|
||||||
|
#include "components/crash/core/common/crash_keys.h"
|
||||||
|
#include "content/public/common/content_paths.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_POSIX)
|
||||||
|
#include "base/lazy_instance.h"
|
||||||
|
#include "libcef/common/crash_reporter_client.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
||||||
|
#include "components/crash/content/app/breakpad_linux.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
#include "libcef/common/crash_reporting_win.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace crash_reporting {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool g_crash_reporting_enabled = false;
|
||||||
|
|
||||||
|
#if defined(OS_POSIX)
|
||||||
|
base::LazyInstance<CefCrashReporterClient>::Leaky g_crash_reporter_client =
|
||||||
|
LAZY_INSTANCE_INITIALIZER;
|
||||||
|
|
||||||
|
void InitCrashReporter(const base::CommandLine& command_line,
|
||||||
|
const std::string& process_type) {
|
||||||
|
CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
|
||||||
|
if (!crash_client->HasCrashConfigFile())
|
||||||
|
return;
|
||||||
|
|
||||||
|
crash_reporter::SetCrashReporterClient(crash_client);
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX)
|
||||||
|
// TODO(mark): Right now, InitializeCrashpad() needs to be called after
|
||||||
|
// CommandLine::Init() and configuration of chrome::DIR_CRASH_DUMPS. Ideally,
|
||||||
|
// Crashpad initialization could occur sooner, preferably even before the
|
||||||
|
// framework dylib is even loaded, to catch potential early crashes.
|
||||||
|
crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
|
||||||
|
|
||||||
|
// Mac Chrome is packaged with a main app bundle and a helper app bundle.
|
||||||
|
// The main app bundle should only be used for the browser process, so it
|
||||||
|
// should never see a --type switch (switches::kProcessType). Likewise,
|
||||||
|
// the helper should always have a --type switch.
|
||||||
|
//
|
||||||
|
// This check is done this late so there is already a call to
|
||||||
|
// base::mac::IsBackgroundOnlyProcess(), so there is no change in
|
||||||
|
// startup/initialization order.
|
||||||
|
|
||||||
|
// The helper's Info.plist marks it as a background only app.
|
||||||
|
if (base::mac::IsBackgroundOnlyProcess()) {
|
||||||
|
CHECK(command_line.HasSwitch(switches::kProcessType) &&
|
||||||
|
!process_type.empty())
|
||||||
|
<< "Helper application requires --type.";
|
||||||
|
} else {
|
||||||
|
CHECK(!command_line.HasSwitch(switches::kProcessType) &&
|
||||||
|
process_type.empty())
|
||||||
|
<< "Main application forbids --type, saw " << process_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_crash_reporting_enabled = true;
|
||||||
|
#else // !defined(OS_MACOSX)
|
||||||
|
breakpad::SetCrashServerURL(crash_client->GetCrashServerURL());
|
||||||
|
|
||||||
|
if (process_type != switches::kZygoteProcess) {
|
||||||
|
// Crash reporting for subprocesses created using the zygote will be
|
||||||
|
// initialized in ZygoteForked.
|
||||||
|
breakpad::InitCrashReporter(process_type);
|
||||||
|
|
||||||
|
g_crash_reporting_enabled = true;
|
||||||
|
}
|
||||||
|
#endif // !defined(OS_MACOSX)
|
||||||
|
}
|
||||||
|
#endif // defined(OS_POSIX)
|
||||||
|
|
||||||
|
// Used to exclude command-line flags from crash reporting.
|
||||||
|
bool IsBoringCEFSwitch(const std::string& flag) {
|
||||||
|
if (crash_keys::IsBoringChromeSwitch(flag))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
static const char* const kIgnoreSwitches[] = {
|
||||||
|
// CEF internals.
|
||||||
|
switches::kLogFile,
|
||||||
|
|
||||||
|
// Chromium internals.
|
||||||
|
"content-image-texture-target",
|
||||||
|
"mojo-platform-channel-handle",
|
||||||
|
"primordial-pipe-token",
|
||||||
|
"service-request-channel-token",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!base::StartsWith(flag, "--", base::CompareCase::SENSITIVE))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t end = flag.find("=");
|
||||||
|
size_t len = (end == std::string::npos) ? flag.length() - 2 : end - 2;
|
||||||
|
for (size_t i = 0; i < arraysize(kIgnoreSwitches); ++i) {
|
||||||
|
if (flag.compare(2, len, kIgnoreSwitches[i]) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#if defined(OS_POSIX)
|
||||||
|
// Be aware that logging is not initialized at the time this method is called.
|
||||||
|
void BasicStartupComplete(base::CommandLine* command_line) {
|
||||||
|
CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
|
||||||
|
if (crash_client->ReadCrashConfigFile()) {
|
||||||
|
#if !defined(OS_MACOSX)
|
||||||
|
// Breakpad requires this switch.
|
||||||
|
command_line->AppendSwitch(switches::kEnableCrashReporter);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PreSandboxStartup(const base::CommandLine& command_line,
|
||||||
|
const std::string& process_type) {
|
||||||
|
#if defined(OS_POSIX)
|
||||||
|
// Initialize crash reporting here on macOS and Linux. Crash reporting on
|
||||||
|
// Windows is initialized from context.cc.
|
||||||
|
InitCrashReporter(command_line, process_type);
|
||||||
|
#elif defined(OS_WIN)
|
||||||
|
// Initialize crash key globals in the module (libcef) address space.
|
||||||
|
g_crash_reporting_enabled =
|
||||||
|
crash_reporting_win::InitializeCrashReportingForModule();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (g_crash_reporting_enabled) {
|
||||||
|
LOG(INFO) << "Crash reporting enabled for process: " <<
|
||||||
|
(process_type.empty() ? "browser" : process_type.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// After platform crash reporting have been initialized, store the command
|
||||||
|
// line for crash reporting.
|
||||||
|
crash_keys::SetSwitchesFromCommandLine(command_line, &IsBoringCEFSwitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
|
||||||
|
void ZygoteForked(base::CommandLine* command_line,
|
||||||
|
const std::string& process_type) {
|
||||||
|
CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
|
||||||
|
if (crash_client->HasCrashConfigFile()) {
|
||||||
|
// Breakpad requires this switch.
|
||||||
|
command_line->AppendSwitch(switches::kEnableCrashReporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
InitCrashReporter(*command_line, process_type);
|
||||||
|
|
||||||
|
if (g_crash_reporting_enabled) {
|
||||||
|
LOG(INFO) << "Crash reporting enabled for process: " << process_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the command line for the newly spawned process.
|
||||||
|
crash_keys::SetSwitchesFromCommandLine(*command_line, &IsBoringCEFSwitch);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace crash_reporting
|
||||||
|
|
||||||
|
bool CefCrashReportingEnabled() {
|
||||||
|
return crash_reporting::g_crash_reporting_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefSetCrashKeyValue(const CefString& key, const CefString& value) {
|
||||||
|
base::debug::SetCrashKeyValue(key.ToString(), value.ToString());
|
||||||
|
}
|
29
libcef/common/crash_reporting.h
Normal file
29
libcef/common/crash_reporting.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
|
||||||
|
// 2016 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 <string>
|
||||||
|
|
||||||
|
#include "build/build_config.h"
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
class CommandLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace crash_reporting {
|
||||||
|
|
||||||
|
// Functions are called from similarly named methods in CefMainDelegate.
|
||||||
|
|
||||||
|
#if defined(OS_POSIX)
|
||||||
|
void BasicStartupComplete(base::CommandLine* command_line);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PreSandboxStartup(const base::CommandLine& command_line,
|
||||||
|
const std::string& process_type);
|
||||||
|
|
||||||
|
#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
|
||||||
|
void ZygoteForked(base::CommandLine* command_line,
|
||||||
|
const std::string& process_type);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace crash_reporting
|
120
libcef/common/crash_reporting_win.cc
Normal file
120
libcef/common/crash_reporting_win.cc
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
|
||||||
|
// 2016 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 <windows.h>
|
||||||
|
|
||||||
|
#include "libcef/common/crash_reporting_win.h"
|
||||||
|
|
||||||
|
#include "base/debug/crash_logging.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
|
#include "chrome/common/chrome_constants.h"
|
||||||
|
#include "components/crash/core/common/crash_keys.h"
|
||||||
|
|
||||||
|
namespace crash_reporting_win {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// exported in crash_reporter_client.cc:
|
||||||
|
// size_t __declspec(dllexport) __cdecl GetCrashKeyCountImpl.
|
||||||
|
typedef size_t(__cdecl* GetCrashKeyCount)();
|
||||||
|
|
||||||
|
// exported in crash_reporter_client.cc:
|
||||||
|
// bool __declspec(dllexport) __cdecl GetCrashKeyImpl.
|
||||||
|
typedef bool(__cdecl* GetCrashKey)(size_t, const char**, size_t*);
|
||||||
|
|
||||||
|
size_t GetCrashKeyCountTrampoline() {
|
||||||
|
static GetCrashKeyCount get_crash_key_count = []() {
|
||||||
|
HMODULE elf_module = GetModuleHandle(chrome::kChromeElfDllName);
|
||||||
|
return reinterpret_cast<GetCrashKeyCount>(
|
||||||
|
elf_module ? GetProcAddress(elf_module, "GetCrashKeyCountImpl")
|
||||||
|
: nullptr);
|
||||||
|
}();
|
||||||
|
if (get_crash_key_count) {
|
||||||
|
return (get_crash_key_count)();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetCrashKeyTrampoline(size_t index,
|
||||||
|
const char** key_name,
|
||||||
|
size_t* max_length) {
|
||||||
|
static GetCrashKey get_crash_key = []() {
|
||||||
|
HMODULE elf_module = GetModuleHandle(chrome::kChromeElfDllName);
|
||||||
|
return reinterpret_cast<GetCrashKey>(
|
||||||
|
elf_module ? GetProcAddress(elf_module, "GetCrashKeyImpl")
|
||||||
|
: nullptr);
|
||||||
|
}();
|
||||||
|
if (get_crash_key) {
|
||||||
|
return (get_crash_key)(index, key_name, max_length);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// From chrome/common/child_process_logging_win.cc:
|
||||||
|
|
||||||
|
// exported in breakpad_win.cc/crashpad_win.cc:
|
||||||
|
// void __declspec(dllexport) __cdecl SetCrashKeyValueImpl.
|
||||||
|
typedef void(__cdecl* SetCrashKeyValue)(const wchar_t*, const wchar_t*);
|
||||||
|
|
||||||
|
// exported in breakpad_win.cc/crashpad_win.cc:
|
||||||
|
// void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl.
|
||||||
|
typedef void(__cdecl* ClearCrashKeyValue)(const wchar_t*);
|
||||||
|
|
||||||
|
void SetCrashKeyValueTrampoline(const base::StringPiece& key,
|
||||||
|
const base::StringPiece& value) {
|
||||||
|
static SetCrashKeyValue set_crash_key = []() {
|
||||||
|
HMODULE elf_module = GetModuleHandle(chrome::kChromeElfDllName);
|
||||||
|
return reinterpret_cast<SetCrashKeyValue>(
|
||||||
|
elf_module ? GetProcAddress(elf_module, "SetCrashKeyValueImpl")
|
||||||
|
: nullptr);
|
||||||
|
}();
|
||||||
|
if (set_crash_key) {
|
||||||
|
(set_crash_key)(base::UTF8ToWide(key).data(),
|
||||||
|
base::UTF8ToWide(value).data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearCrashKeyValueTrampoline(const base::StringPiece& key) {
|
||||||
|
static ClearCrashKeyValue clear_crash_key = []() {
|
||||||
|
HMODULE elf_module = GetModuleHandle(chrome::kChromeElfDllName);
|
||||||
|
return reinterpret_cast<ClearCrashKeyValue>(
|
||||||
|
elf_module ? GetProcAddress(elf_module, "ClearCrashKeyValueImpl")
|
||||||
|
: nullptr);
|
||||||
|
}();
|
||||||
|
if (clear_crash_key)
|
||||||
|
(clear_crash_key)(base::UTF8ToWide(key).data());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool InitializeCrashReportingForModule() {
|
||||||
|
base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValueTrampoline,
|
||||||
|
&ClearCrashKeyValueTrampoline);
|
||||||
|
|
||||||
|
std::vector<base::debug::CrashKey> keys;
|
||||||
|
|
||||||
|
size_t key_ct = GetCrashKeyCountTrampoline();
|
||||||
|
if (key_ct > 0U) {
|
||||||
|
keys.reserve(key_ct);
|
||||||
|
|
||||||
|
const char* key_name;
|
||||||
|
size_t max_length;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < key_ct; ++i) {
|
||||||
|
if (GetCrashKeyTrampoline(i, &key_name, &max_length))
|
||||||
|
keys.push_back({key_name, max_length});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keys.empty()) {
|
||||||
|
base::debug::InitCrashKeys(&keys[0], keys.size(),
|
||||||
|
crash_keys::kChunkMaxLength);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crash_reporting_win
|
11
libcef/common/crash_reporting_win.h
Normal file
11
libcef/common/crash_reporting_win.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
|
||||||
|
// 2016 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.
|
||||||
|
|
||||||
|
namespace crash_reporting_win {
|
||||||
|
|
||||||
|
// Called from libcef to initialize crash key globals. Retrieves the necessary
|
||||||
|
// state from chrome_elf via exported functions.
|
||||||
|
bool InitializeCrashReportingForModule();
|
||||||
|
|
||||||
|
} // namespace crash_reporting_win
|
@ -7,7 +7,7 @@
|
|||||||
#include "libcef/browser/context.h"
|
#include "libcef/browser/context.h"
|
||||||
#include "libcef/common/cef_switches.h"
|
#include "libcef/common/cef_switches.h"
|
||||||
#include "libcef/common/command_line_impl.h"
|
#include "libcef/common/command_line_impl.h"
|
||||||
#include "libcef/common/crash_reporter_client.h"
|
#include "libcef/common/crash_reporting.h"
|
||||||
#include "libcef/common/extensions/extensions_util.h"
|
#include "libcef/common/extensions/extensions_util.h"
|
||||||
#include "libcef/renderer/content_renderer_client.h"
|
#include "libcef/renderer/content_renderer_client.h"
|
||||||
#include "libcef/utility/content_utility_client.h"
|
#include "libcef/utility/content_utility_client.h"
|
||||||
@ -16,7 +16,6 @@
|
|||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "base/files/file_util.h"
|
#include "base/files/file_util.h"
|
||||||
#include "base/lazy_instance.h"
|
|
||||||
#include "base/path_service.h"
|
#include "base/path_service.h"
|
||||||
#include "base/strings/string_number_conversions.h"
|
#include "base/strings/string_number_conversions.h"
|
||||||
#include "base/strings/string_util.h"
|
#include "base/strings/string_util.h"
|
||||||
@ -57,18 +56,11 @@
|
|||||||
|
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
#include "libcef/common/util_mac.h"
|
#include "libcef/common/util_mac.h"
|
||||||
#include "base/mac/os_crash_dumps.h"
|
|
||||||
#include "base/mac/bundle_locations.h"
|
#include "base/mac/bundle_locations.h"
|
||||||
#include "base/mac/foundation_util.h"
|
#include "base/mac/foundation_util.h"
|
||||||
#include "components/crash/content/app/crashpad.h"
|
|
||||||
#include "components/crash/core/common/crash_keys.h"
|
|
||||||
#include "content/public/common/content_paths.h"
|
#include "content/public/common/content_paths.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
|
||||||
#include "components/crash/content/app/breakpad_linux.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
#include "base/environment.h"
|
#include "base/environment.h"
|
||||||
#include "base/nix/xdg_util.h"
|
#include "base/nix/xdg_util.h"
|
||||||
@ -76,11 +68,6 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#if defined(OS_POSIX)
|
|
||||||
base::LazyInstance<CefCrashReporterClient>::Leaky g_crash_reporter_client =
|
|
||||||
LAZY_INSTANCE_INITIALIZER;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
|
|
||||||
base::FilePath GetFrameworksPath() {
|
base::FilePath GetFrameworksPath() {
|
||||||
@ -327,6 +314,12 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
|
|||||||
std::string process_type =
|
std::string process_type =
|
||||||
command_line->GetSwitchValueASCII(switches::kProcessType);
|
command_line->GetSwitchValueASCII(switches::kProcessType);
|
||||||
|
|
||||||
|
#if defined(OS_POSIX)
|
||||||
|
// Read the crash configuration file. Platforms using Breakpad also add a
|
||||||
|
// command-line switch. On Windows this is done from chrome_elf.
|
||||||
|
crash_reporting::BasicStartupComplete(command_line);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (process_type.empty()) {
|
if (process_type.empty()) {
|
||||||
// In the browser process. Populate the global command-line object.
|
// In the browser process. Populate the global command-line object.
|
||||||
const CefSettings& settings = CefContext::Get()->settings();
|
const CefSettings& settings = CefContext::Get()->settings();
|
||||||
@ -524,18 +517,6 @@ void CefMainDelegate::PreSandboxStartup() {
|
|||||||
const std::string& process_type =
|
const std::string& process_type =
|
||||||
command_line->GetSwitchValueASCII(switches::kProcessType);
|
command_line->GetSwitchValueASCII(switches::kProcessType);
|
||||||
|
|
||||||
#if defined(OS_POSIX)
|
|
||||||
if (command_line->HasSwitch(switches::kEnableCrashReporter)) {
|
|
||||||
crash_reporter::SetCrashReporterClient(g_crash_reporter_client.Pointer());
|
|
||||||
#if defined(OS_MACOSX)
|
|
||||||
InitMacCrashReporter(*command_line, process_type);
|
|
||||||
#else
|
|
||||||
if (process_type != switches::kZygoteProcess)
|
|
||||||
breakpad::InitCrashReporter(process_type);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif // defined(OS_POSIX)
|
|
||||||
|
|
||||||
if (process_type.empty()) {
|
if (process_type.empty()) {
|
||||||
// Only override these paths when executing the main process.
|
// Only override these paths when executing the main process.
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
@ -544,9 +525,13 @@ void CefMainDelegate::PreSandboxStartup() {
|
|||||||
|
|
||||||
OverridePepperFlashSystemPluginPath();
|
OverridePepperFlashSystemPluginPath();
|
||||||
|
|
||||||
// Paths used to locate spell checking dictionary files.
|
|
||||||
const base::FilePath& user_data_path = GetUserDataPath();
|
const base::FilePath& user_data_path = GetUserDataPath();
|
||||||
PathService::Override(chrome::DIR_USER_DATA, user_data_path);
|
PathService::Override(chrome::DIR_USER_DATA, user_data_path);
|
||||||
|
|
||||||
|
// Path used for crash dumps.
|
||||||
|
PathService::Override(chrome::DIR_CRASH_DUMPS, user_data_path);
|
||||||
|
|
||||||
|
// Path used for spell checking dictionary files.
|
||||||
PathService::OverrideAndCreateIfNeeded(
|
PathService::OverrideAndCreateIfNeeded(
|
||||||
chrome::DIR_APP_DICTIONARIES,
|
chrome::DIR_APP_DICTIONARIES,
|
||||||
user_data_path.AppendASCII("Dictionaries"),
|
user_data_path.AppendASCII("Dictionaries"),
|
||||||
@ -557,6 +542,10 @@ void CefMainDelegate::PreSandboxStartup() {
|
|||||||
if (command_line->HasSwitch(switches::kDisablePackLoading))
|
if (command_line->HasSwitch(switches::kDisablePackLoading))
|
||||||
content_client_.set_pack_loading_disabled(true);
|
content_client_.set_pack_loading_disabled(true);
|
||||||
|
|
||||||
|
// Initialize crash reporting state for this process/module.
|
||||||
|
// chrome::DIR_CRASH_DUMPS must be configured before calling this function.
|
||||||
|
crash_reporting::PreSandboxStartup(*command_line, process_type);
|
||||||
|
|
||||||
InitializeResourceBundle();
|
InitializeResourceBundle();
|
||||||
chrome::InitializePDF();
|
chrome::InitializePDF();
|
||||||
}
|
}
|
||||||
@ -609,13 +598,12 @@ void CefMainDelegate::ProcessExiting(const std::string& process_type) {
|
|||||||
|
|
||||||
#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
|
#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
|
||||||
void CefMainDelegate::ZygoteForked() {
|
void CefMainDelegate::ZygoteForked() {
|
||||||
const base::CommandLine* command_line =
|
base::CommandLine* command_line =
|
||||||
base::CommandLine::ForCurrentProcess();
|
base::CommandLine::ForCurrentProcess();
|
||||||
if (command_line->HasSwitch(switches::kEnableCrashReporter)) {
|
const std::string& process_type = command_line->GetSwitchValueASCII(
|
||||||
const std::string& process_type = command_line->GetSwitchValueASCII(
|
|
||||||
switches::kProcessType);
|
switches::kProcessType);
|
||||||
breakpad::InitCrashReporter(process_type);
|
// Initialize crash reporting state for the newly forked process.
|
||||||
}
|
crash_reporting::ZygoteForked(command_line, process_type);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -757,51 +745,3 @@ void CefMainDelegate::InitializeResourceBundle() {
|
|||||||
content_client_.set_allow_pack_file_load(false);
|
content_client_.set_allow_pack_file_load(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OS_MACOSX)
|
|
||||||
// Based on ChromeMainDelegate::InitMacCrashReporter.
|
|
||||||
void CefMainDelegate::InitMacCrashReporter(
|
|
||||||
const base::CommandLine& command_line,
|
|
||||||
const std::string& process_type) {
|
|
||||||
// TODO(mark): Right now, InitializeCrashpad() needs to be called after
|
|
||||||
// CommandLine::Init() and chrome::RegisterPathProvider(). Ideally, Crashpad
|
|
||||||
// initialization could occur sooner, preferably even before the framework
|
|
||||||
// dylib is even loaded, to catch potential early crashes.
|
|
||||||
|
|
||||||
const bool browser_process = process_type.empty();
|
|
||||||
const bool install_from_dmg_relauncher_process =
|
|
||||||
process_type == switches::kRelauncherProcess &&
|
|
||||||
command_line.HasSwitch(switches::kRelauncherProcessDMGDevice);
|
|
||||||
|
|
||||||
const bool initial_client =
|
|
||||||
browser_process || install_from_dmg_relauncher_process;
|
|
||||||
|
|
||||||
crash_reporter::InitializeCrashpad(initial_client, process_type);
|
|
||||||
|
|
||||||
if (!browser_process) {
|
|
||||||
std::string metrics_client_id =
|
|
||||||
command_line.GetSwitchValueASCII(switches::kMetricsClientID);
|
|
||||||
crash_keys::SetMetricsClientIdFromGUID(metrics_client_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mac Chrome is packaged with a main app bundle and a helper app bundle.
|
|
||||||
// The main app bundle should only be used for the browser process, so it
|
|
||||||
// should never see a --type switch (switches::kProcessType). Likewise,
|
|
||||||
// the helper should always have a --type switch.
|
|
||||||
//
|
|
||||||
// This check is done this late so there is already a call to
|
|
||||||
// base::mac::IsBackgroundOnlyProcess(), so there is no change in
|
|
||||||
// startup/initialization order.
|
|
||||||
|
|
||||||
// The helper's Info.plist marks it as a background only app.
|
|
||||||
if (base::mac::IsBackgroundOnlyProcess()) {
|
|
||||||
CHECK(command_line.HasSwitch(switches::kProcessType) &&
|
|
||||||
!process_type.empty())
|
|
||||||
<< "Helper application requires --type.";
|
|
||||||
} else {
|
|
||||||
CHECK(!command_line.HasSwitch(switches::kProcessType) &&
|
|
||||||
process_type.empty())
|
|
||||||
<< "Main application forbids --type, saw " << process_type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // defined(OS_MACOSX)
|
|
@ -56,11 +56,6 @@ class CefMainDelegate : public content::ContentMainDelegate {
|
|||||||
private:
|
private:
|
||||||
void InitializeResourceBundle();
|
void InitializeResourceBundle();
|
||||||
|
|
||||||
#if defined(OS_MACOSX)
|
|
||||||
void InitMacCrashReporter(const base::CommandLine& command_line,
|
|
||||||
const std::string& process_type);
|
|
||||||
#endif // defined(OS_MACOSX)
|
|
||||||
|
|
||||||
std::unique_ptr<content::BrowserMainRunner> browser_runner_;
|
std::unique_ptr<content::BrowserMainRunner> browser_runner_;
|
||||||
std::unique_ptr<base::Thread> ui_thread_;
|
std::unique_ptr<base::Thread> ui_thread_;
|
||||||
|
|
||||||
|
19
libcef/features/BUILD.gn
Normal file
19
libcef/features/BUILD.gn
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
import("//build/buildflag_header.gni")
|
||||||
|
import("//cef/libcef/features/features.gni")
|
||||||
|
|
||||||
|
# This file is in a separate directory so all targets in the build can refer to
|
||||||
|
# the buildflag header to get the necessary preprocessor defines without
|
||||||
|
# bringing in any CEF targets. Other targets can depend on this target
|
||||||
|
# regardless of whether CEF is being built.
|
||||||
|
|
||||||
|
buildflag_header("features") {
|
||||||
|
header = "features.h"
|
||||||
|
|
||||||
|
flags = [
|
||||||
|
"ENABLE_CEF=$enable_cef",
|
||||||
|
]
|
||||||
|
}
|
7
libcef/features/features.gni
Normal file
7
libcef/features/features.gni
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
declare_args() {
|
||||||
|
enable_cef = true
|
||||||
|
}
|
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include "include/cef_app.h"
|
#include "include/cef_app.h"
|
||||||
#include "include/capi/cef_app_capi.h"
|
#include "include/capi/cef_app_capi.h"
|
||||||
|
#include "include/cef_crash_util.h"
|
||||||
|
#include "include/capi/cef_crash_util_capi.h"
|
||||||
#include "include/cef_file_util.h"
|
#include "include/cef_file_util.h"
|
||||||
#include "include/capi/cef_file_util_capi.h"
|
#include "include/capi/cef_file_util_capi.h"
|
||||||
#include "include/cef_geolocation.h"
|
#include "include/cef_geolocation.h"
|
||||||
@ -391,6 +393,35 @@ CEF_EXPORT void cef_enable_highdpi_support() {
|
|||||||
CefEnableHighDPISupport();
|
CefEnableHighDPISupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CEF_EXPORT int cef_crash_reporting_enabled() {
|
||||||
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
bool _retval = CefCrashReportingEnabled();
|
||||||
|
|
||||||
|
// Return type: bool
|
||||||
|
return _retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
CEF_EXPORT void cef_set_crash_key_value(const cef_string_t* key,
|
||||||
|
const cef_string_t* value) {
|
||||||
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
|
|
||||||
|
// Verify param: key; type: string_byref_const
|
||||||
|
DCHECK(key);
|
||||||
|
if (!key)
|
||||||
|
return;
|
||||||
|
// Verify param: value; type: string_byref_const
|
||||||
|
DCHECK(value);
|
||||||
|
if (!value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
CefSetCrashKeyValue(
|
||||||
|
CefString(key),
|
||||||
|
CefString(value));
|
||||||
|
}
|
||||||
|
|
||||||
CEF_EXPORT int cef_create_directory(const cef_string_t* full_path) {
|
CEF_EXPORT int cef_create_directory(const cef_string_t* full_path) {
|
||||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include "include/cef_app.h"
|
#include "include/cef_app.h"
|
||||||
#include "include/capi/cef_app_capi.h"
|
#include "include/capi/cef_app_capi.h"
|
||||||
|
#include "include/cef_crash_util.h"
|
||||||
|
#include "include/capi/cef_crash_util_capi.h"
|
||||||
#include "include/cef_file_util.h"
|
#include "include/cef_file_util.h"
|
||||||
#include "include/capi/cef_file_util_capi.h"
|
#include "include/capi/cef_file_util_capi.h"
|
||||||
#include "include/cef_geolocation.h"
|
#include "include/cef_geolocation.h"
|
||||||
@ -383,6 +385,35 @@ CEF_GLOBAL void CefEnableHighDPISupport() {
|
|||||||
cef_enable_highdpi_support();
|
cef_enable_highdpi_support();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CEF_GLOBAL bool CefCrashReportingEnabled() {
|
||||||
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
int _retval = cef_crash_reporting_enabled();
|
||||||
|
|
||||||
|
// Return type: bool
|
||||||
|
return _retval?true:false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CEF_GLOBAL void CefSetCrashKeyValue(const CefString& key,
|
||||||
|
const CefString& value) {
|
||||||
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
|
|
||||||
|
// Verify param: key; type: string_byref_const
|
||||||
|
DCHECK(!key.empty());
|
||||||
|
if (key.empty())
|
||||||
|
return;
|
||||||
|
// Verify param: value; type: string_byref_const
|
||||||
|
DCHECK(!value.empty());
|
||||||
|
if (value.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
cef_set_crash_key_value(
|
||||||
|
key.GetStruct(),
|
||||||
|
value.GetStruct());
|
||||||
|
}
|
||||||
|
|
||||||
CEF_GLOBAL bool CefCreateDirectory(const CefString& full_path) {
|
CEF_GLOBAL bool CefCreateDirectory(const CefString& full_path) {
|
||||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||||
|
|
||||||
|
@ -294,4 +294,19 @@ patches = [
|
|||||||
'name': 'render_widget_latency_2060',
|
'name': 'render_widget_latency_2060',
|
||||||
'path': '../',
|
'path': '../',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
# Implement breakpad/crashpad customization required by CEF.
|
||||||
|
# https://bitbucket.org/chromiumembedded/cef/issues/1995
|
||||||
|
'name': 'crashpad_1995',
|
||||||
|
'path': '../',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Support customization of crash report pruning limits.
|
||||||
|
# https://bugs.chromium.org/p/crashpad/issues/detail?id=142
|
||||||
|
#
|
||||||
|
# Implement better rate-limiting/retry logic.
|
||||||
|
# https://bugs.chromium.org/p/crashpad/issues/detail?id=23
|
||||||
|
'name': 'crashpad_tp_1995',
|
||||||
|
'path': '../third_party/crashpad/',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
509
patch/patches/crashpad_1995.patch
Normal file
509
patch/patches/crashpad_1995.patch
Normal file
@ -0,0 +1,509 @@
|
|||||||
|
diff --git build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn
|
||||||
|
index 6cd8b9f..dfbbdc6 100644
|
||||||
|
--- build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn
|
||||||
|
+++ build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn
|
||||||
|
@@ -2,6 +2,8 @@
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
+import("//cef/libcef/features/features.gni")
|
||||||
|
+
|
||||||
|
static_library("handler_lib") {
|
||||||
|
sources = [
|
||||||
|
"crash_report_upload_thread.cc",
|
||||||
|
@@ -26,8 +28,18 @@ static_library("handler_lib") {
|
||||||
|
"../snapshot",
|
||||||
|
"../tools:tool_support",
|
||||||
|
"//base",
|
||||||
|
+ "//cef/libcef/features",
|
||||||
|
]
|
||||||
|
|
||||||
|
+ if (enable_cef) {
|
||||||
|
+ sources += [
|
||||||
|
+ "//cef/libcef/common/cef_crash_report_upload_thread.cc",
|
||||||
|
+ "//cef/libcef/common/cef_crash_report_upload_thread.h",
|
||||||
|
+ ]
|
||||||
|
+
|
||||||
|
+ include_dirs += [ "//cef" ]
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (is_win) {
|
||||||
|
cflags = [ "/wd4201" ]
|
||||||
|
}
|
||||||
|
diff --git chrome/common/crash_keys.cc chrome/common/crash_keys.cc
|
||||||
|
index 800f704..e4b4063 100644
|
||||||
|
--- chrome/common/crash_keys.cc
|
||||||
|
+++ chrome/common/crash_keys.cc
|
||||||
|
@@ -4,6 +4,8 @@
|
||||||
|
|
||||||
|
#include "chrome/common/crash_keys.h"
|
||||||
|
|
||||||
|
+#include <iterator>
|
||||||
|
+
|
||||||
|
#include "base/base_switches.h"
|
||||||
|
#include "base/command_line.h"
|
||||||
|
#include "base/format_macros.h"
|
||||||
|
@@ -94,7 +96,7 @@ const char kViewCount[] = "view-count";
|
||||||
|
|
||||||
|
const char kZeroEncodeDetails[] = "zero-encode-details";
|
||||||
|
|
||||||
|
-size_t RegisterChromeCrashKeys() {
|
||||||
|
+void GetChromeCrashKeys(std::vector<base::debug::CrashKey>& keys) {
|
||||||
|
// The following keys may be chunked by the underlying crash logging system,
|
||||||
|
// but ultimately constitute a single key-value pair.
|
||||||
|
//
|
||||||
|
@@ -250,10 +252,16 @@ size_t RegisterChromeCrashKeys() {
|
||||||
|
|
||||||
|
// This dynamic set of keys is used for sets of key value pairs when gathering
|
||||||
|
// a collection of data, like command line switches or extension IDs.
|
||||||
|
- std::vector<base::debug::CrashKey> keys(
|
||||||
|
- fixed_keys, fixed_keys + arraysize(fixed_keys));
|
||||||
|
+ keys.reserve(keys.size() + arraysize(fixed_keys));
|
||||||
|
+ std::copy(fixed_keys, fixed_keys + arraysize(fixed_keys),
|
||||||
|
+ std::back_inserter(keys));
|
||||||
|
|
||||||
|
crash_keys::GetCrashKeysForCommandLineSwitches(&keys);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+size_t RegisterChromeCrashKeys() {
|
||||||
|
+ std::vector<base::debug::CrashKey> keys;
|
||||||
|
+ GetChromeCrashKeys(keys);
|
||||||
|
|
||||||
|
// Register the extension IDs.
|
||||||
|
{
|
||||||
|
@@ -287,7 +295,7 @@ size_t RegisterChromeCrashKeys() {
|
||||||
|
return base::debug::InitCrashKeys(&keys.at(0), keys.size(), kChunkMaxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static bool IsBoringSwitch(const std::string& flag) {
|
||||||
|
+bool IsBoringChromeSwitch(const std::string& flag) {
|
||||||
|
static const char* const kIgnoreSwitches[] = {
|
||||||
|
switches::kEnableLogging,
|
||||||
|
switches::kFlagSwitchesBegin,
|
||||||
|
@@ -343,7 +351,7 @@ static bool IsBoringSwitch(const std::string& flag) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCrashKeysFromCommandLine(const base::CommandLine& command_line) {
|
||||||
|
- return SetSwitchesFromCommandLine(command_line, &IsBoringSwitch);
|
||||||
|
+ return SetSwitchesFromCommandLine(command_line, &IsBoringChromeSwitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetActiveExtensions(const std::set<std::string>& extensions) {
|
||||||
|
diff --git chrome/common/crash_keys.h chrome/common/crash_keys.h
|
||||||
|
index 6f66031..1abcdf8 100644
|
||||||
|
--- chrome/common/crash_keys.h
|
||||||
|
+++ chrome/common/crash_keys.h
|
||||||
|
@@ -23,10 +23,18 @@ class CommandLine;
|
||||||
|
|
||||||
|
namespace crash_keys {
|
||||||
|
|
||||||
|
+// Returns the list of potential crash keys that can be sent to the crash
|
||||||
|
+// server.
|
||||||
|
+void GetChromeCrashKeys(std::vector<base::debug::CrashKey>& keys);
|
||||||
|
+
|
||||||
|
// Registers all of the potential crash keys that can be sent to the crash
|
||||||
|
// reporting server. Returns the size of the union of all keys.
|
||||||
|
size_t RegisterChromeCrashKeys();
|
||||||
|
|
||||||
|
+// Returns true if the specified command-line flag should be excluded from
|
||||||
|
+// crash reporting.
|
||||||
|
+bool IsBoringChromeSwitch(const std::string& flag);
|
||||||
|
+
|
||||||
|
// Sets the kNumSwitches key and the set of keys named using kSwitchFormat based
|
||||||
|
// on the given |command_line|.
|
||||||
|
void SetCrashKeysFromCommandLine(const base::CommandLine& command_line);
|
||||||
|
diff --git chrome/install_static/install_util.cc chrome/install_static/install_util.cc
|
||||||
|
index edec76d..1db1c9c 100644
|
||||||
|
--- chrome/install_static/install_util.cc
|
||||||
|
+++ chrome/install_static/install_util.cc
|
||||||
|
@@ -473,7 +473,9 @@ bool IsNonBrowserProcess() {
|
||||||
|
return g_process_type == ProcessType::NON_BROWSER_PROCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
-bool GetDefaultUserDataDirectory(std::wstring* result) {
|
||||||
|
+bool GetDefaultUserDataDirectory(
|
||||||
|
+ std::wstring* result,
|
||||||
|
+ const std::wstring& install_sub_directory) {
|
||||||
|
// This environment variable should be set on Windows Vista and later
|
||||||
|
// (https://msdn.microsoft.com/library/windows/desktop/dd378457.aspx).
|
||||||
|
std::wstring user_data_dir = GetEnvironmentString16(L"LOCALAPPDATA");
|
||||||
|
@@ -493,17 +495,23 @@ bool GetDefaultUserDataDirectory(std::wstring* result) {
|
||||||
|
result->swap(user_data_dir);
|
||||||
|
if ((*result)[result->length() - 1] != L'\\')
|
||||||
|
result->push_back(L'\\');
|
||||||
|
- AppendChromeInstallSubDirectory(result, true /* include_suffix */);
|
||||||
|
+ if (!install_sub_directory.empty()) {
|
||||||
|
+ result->append(install_sub_directory);
|
||||||
|
+ } else {
|
||||||
|
+ AppendChromeInstallSubDirectory(result, true /* include_suffix */);
|
||||||
|
+ }
|
||||||
|
result->push_back(L'\\');
|
||||||
|
result->append(kUserDataDirname);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
-bool GetDefaultCrashDumpLocation(std::wstring* crash_dir) {
|
||||||
|
+bool GetDefaultCrashDumpLocation(
|
||||||
|
+ std::wstring* crash_dir,
|
||||||
|
+ const std::wstring& install_sub_directory) {
|
||||||
|
// In order to be able to start crash handling very early, we do not rely on
|
||||||
|
// chrome's PathService entries (for DIR_CRASH_DUMPS) being available on
|
||||||
|
// Windows. See https://crbug.com/564398.
|
||||||
|
- if (!GetDefaultUserDataDirectory(crash_dir))
|
||||||
|
+ if (!GetDefaultUserDataDirectory(crash_dir, install_sub_directory))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// We have to make sure the user data dir exists on first run. See
|
||||||
|
diff --git chrome/install_static/install_util.h chrome/install_static/install_util.h
|
||||||
|
index 4ded522..81eba43 100644
|
||||||
|
--- chrome/install_static/install_util.h
|
||||||
|
+++ chrome/install_static/install_util.h
|
||||||
|
@@ -86,14 +86,18 @@ bool IsNonBrowserProcess();
|
||||||
|
// TODO(ananta)
|
||||||
|
// http://crbug.com/604923
|
||||||
|
// Unify this with the Browser Distribution code.
|
||||||
|
-bool GetDefaultUserDataDirectory(std::wstring* result);
|
||||||
|
+bool GetDefaultUserDataDirectory(
|
||||||
|
+ std::wstring* result,
|
||||||
|
+ const std::wstring& install_sub_directory = std::wstring());
|
||||||
|
|
||||||
|
// Populates |crash_dir| with the default crash dump location regardless of
|
||||||
|
// whether DIR_USER_DATA or DIR_CRASH_DUMPS has been overridden.
|
||||||
|
// TODO(ananta)
|
||||||
|
// http://crbug.com/604923
|
||||||
|
// Unify this with the Browser Distribution code.
|
||||||
|
-bool GetDefaultCrashDumpLocation(std::wstring* crash_dir);
|
||||||
|
+bool GetDefaultCrashDumpLocation(
|
||||||
|
+ std::wstring* crash_dir,
|
||||||
|
+ const std::wstring& install_sub_directory = std::wstring());
|
||||||
|
|
||||||
|
// Returns the contents of the specified |variable_name| from the environment
|
||||||
|
// block of the calling process. Returns an empty string if the variable does
|
||||||
|
diff --git chrome_elf/BUILD.gn chrome_elf/BUILD.gn
|
||||||
|
index 0629b6f..9c150b5 100644
|
||||||
|
--- chrome_elf/BUILD.gn
|
||||||
|
+++ chrome_elf/BUILD.gn
|
||||||
|
@@ -7,6 +7,7 @@
|
||||||
|
|
||||||
|
import("//build/config/compiler/compiler.gni")
|
||||||
|
import("//build/config/win/manifest.gni")
|
||||||
|
+import("//cef/libcef/features/features.gni")
|
||||||
|
import("//chrome/process_version_rc_template.gni")
|
||||||
|
import("//testing/test.gni")
|
||||||
|
|
||||||
|
@@ -138,16 +139,40 @@ static_library("blacklist") {
|
||||||
|
|
||||||
|
static_library("crash") {
|
||||||
|
sources = [
|
||||||
|
- "../chrome/app/chrome_crash_reporter_client_win.cc",
|
||||||
|
- "../chrome/app/chrome_crash_reporter_client_win.h",
|
||||||
|
- "../chrome/common/chrome_result_codes.h",
|
||||||
|
"crash/crash_helper.cc",
|
||||||
|
"crash/crash_helper.h",
|
||||||
|
]
|
||||||
|
+
|
||||||
|
+ if (enable_cef) {
|
||||||
|
+ sources += [
|
||||||
|
+ "//cef/libcef/common/crash_reporter_client.cc",
|
||||||
|
+ "//cef/libcef/common/crash_reporter_client.h",
|
||||||
|
+
|
||||||
|
+ # Required for crash_keys::GetChromeCrashKeys.
|
||||||
|
+ # Otherwise we need to copy this array into CEF, which would be difficult
|
||||||
|
+ # to maintain.
|
||||||
|
+ "//chrome/common/crash_keys.cc",
|
||||||
|
+ "//chrome/common/chrome_switches.cc",
|
||||||
|
+ "//components/flags_ui/flags_ui_switches.cc",
|
||||||
|
+ "//content/public/common/content_switches.cc",
|
||||||
|
+
|
||||||
|
+ ]
|
||||||
|
+ include_dirs = [
|
||||||
|
+ "//cef",
|
||||||
|
+ ]
|
||||||
|
+ } else {
|
||||||
|
+ sources += [
|
||||||
|
+ "//chrome/app/chrome_crash_reporter_client_win.cc",
|
||||||
|
+ "//chrome/app/chrome_crash_reporter_client_win.h",
|
||||||
|
+ "//chrome/common/chrome_result_codes.h",
|
||||||
|
+ ]
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
deps = [
|
||||||
|
":hook_util",
|
||||||
|
"//base:base", # This needs to go. DEP of app, crash_keys, client.
|
||||||
|
"//base:base_static", # pe_image
|
||||||
|
+ "//cef/libcef/features",
|
||||||
|
"//chrome/install_static:install_static_util",
|
||||||
|
"//components/crash/content/app:app",
|
||||||
|
"//components/crash/core/common", # crash_keys
|
||||||
|
diff --git chrome_elf/crash/crash_helper.cc chrome_elf/crash/crash_helper.cc
|
||||||
|
index c658fa9..8c4a145 100644
|
||||||
|
--- chrome_elf/crash/crash_helper.cc
|
||||||
|
+++ chrome_elf/crash/crash_helper.cc
|
||||||
|
@@ -11,12 +11,17 @@
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
+#include "cef/libcef/features/features.h"
|
||||||
|
#include "chrome/app/chrome_crash_reporter_client_win.h"
|
||||||
|
#include "chrome_elf/hook_util/hook_util.h"
|
||||||
|
#include "components/crash/content/app/crashpad.h"
|
||||||
|
#include "components/crash/core/common/crash_keys.h"
|
||||||
|
#include "third_party/crashpad/crashpad/client/crashpad_client.h"
|
||||||
|
|
||||||
|
+#if BUILDFLAG(ENABLE_CEF)
|
||||||
|
+#include "cef/libcef/common/crash_reporter_client.h"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Crash handling from elf is only enabled for the chrome.exe process.
|
||||||
|
@@ -74,7 +79,11 @@ bool InitializeCrashReporting() {
|
||||||
|
g_crash_reports = new std::vector<crash_reporter::Report>;
|
||||||
|
g_set_unhandled_exception_filter = new elf_hook::IATHook();
|
||||||
|
|
||||||
|
+#if BUILDFLAG(ENABLE_CEF)
|
||||||
|
+ CefCrashReporterClient::InitializeCrashReportingForProcess();
|
||||||
|
+#else
|
||||||
|
ChromeCrashReporterClient::InitializeCrashReportingForProcess();
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
g_crash_helper_enabled = true;
|
||||||
|
return true;
|
||||||
|
diff --git components/crash/content/app/breakpad_linux.cc components/crash/content/app/breakpad_linux.cc
|
||||||
|
index 9ebc33f..c013b36 100644
|
||||||
|
--- components/crash/content/app/breakpad_linux.cc
|
||||||
|
+++ components/crash/content/app/breakpad_linux.cc
|
||||||
|
@@ -29,6 +29,7 @@
|
||||||
|
#include "base/command_line.h"
|
||||||
|
#include "base/debug/crash_logging.h"
|
||||||
|
#include "base/debug/dump_without_crashing.h"
|
||||||
|
+#include "base/debug/leak_annotations.h"
|
||||||
|
#include "base/files/file_path.h"
|
||||||
|
#include "base/lazy_instance.h"
|
||||||
|
#include "base/linux_util.h"
|
||||||
|
@@ -89,6 +90,7 @@ namespace {
|
||||||
|
|
||||||
|
#if !defined(OS_CHROMEOS)
|
||||||
|
const char kUploadURL[] = "https://clients2.google.com/cr/report";
|
||||||
|
+const char* g_crash_server_url = kUploadURL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool g_is_crash_reporter_enabled = false;
|
||||||
|
@@ -654,7 +656,7 @@ bool CrashDone(const MinidumpDescriptor& minidump,
|
||||||
|
info.process_type_length = 7;
|
||||||
|
info.distro = base::g_linux_distro;
|
||||||
|
info.distro_length = my_strlen(base::g_linux_distro);
|
||||||
|
- info.upload = upload;
|
||||||
|
+ info.upload = upload && g_crash_server_url;
|
||||||
|
info.process_start_time = g_process_start_time;
|
||||||
|
info.oom_size = base::g_oom_size;
|
||||||
|
info.pid = g_pid;
|
||||||
|
@@ -1275,7 +1277,7 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
|
||||||
|
header_content_encoding,
|
||||||
|
header_content_type,
|
||||||
|
post_file,
|
||||||
|
- kUploadURL,
|
||||||
|
+ g_crash_server_url,
|
||||||
|
"--timeout=10", // Set a timeout so we don't hang forever.
|
||||||
|
"--tries=1", // Don't retry if the upload fails.
|
||||||
|
"-O", // output reply to fd 3
|
||||||
|
@@ -1880,6 +1882,17 @@ void InitCrashReporter(const std::string& process_type) {
|
||||||
|
PostEnableBreakpadInitialization();
|
||||||
|
}
|
||||||
|
|
||||||
|
+void SetCrashServerURL(const std::string& url) {
|
||||||
|
+ if (url.empty()) {
|
||||||
|
+ g_crash_server_url = nullptr;
|
||||||
|
+ } else {
|
||||||
|
+ char* new_url = new char[url.size() + 1];
|
||||||
|
+ ANNOTATE_LEAKING_OBJECT_PTR(new_url);
|
||||||
|
+ strcpy(new_url, url.c_str());
|
||||||
|
+ g_crash_server_url = new_url;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
void InitNonBrowserCrashReporterForAndroid(const std::string& process_type) {
|
||||||
|
const base::CommandLine* command_line =
|
||||||
|
diff --git components/crash/content/app/breakpad_linux.h components/crash/content/app/breakpad_linux.h
|
||||||
|
index 3316fa0..df90dbd 100644
|
||||||
|
--- components/crash/content/app/breakpad_linux.h
|
||||||
|
+++ components/crash/content/app/breakpad_linux.h
|
||||||
|
@@ -16,6 +16,9 @@ namespace breakpad {
|
||||||
|
// Turns on the crash reporter in any process.
|
||||||
|
extern void InitCrashReporter(const std::string& process_type);
|
||||||
|
|
||||||
|
+// Set the crash server URL.
|
||||||
|
+void SetCrashServerURL(const std::string& url);
|
||||||
|
+
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
|
||||||
|
const char kWebViewSingleProcessType[] = "webview";
|
||||||
|
diff --git components/crash/content/app/crash_reporter_client.cc components/crash/content/app/crash_reporter_client.cc
|
||||||
|
index 3dfbd99..cb99c1e 100644
|
||||||
|
--- components/crash/content/app/crash_reporter_client.cc
|
||||||
|
+++ components/crash/content/app/crash_reporter_client.cc
|
||||||
|
@@ -141,6 +141,26 @@ bool CrashReporterClient::ReportingIsEnforcedByPolicy(bool* breakpad_enabled) {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+bool CrashReporterClient::EnableBreakpadForProcess(
|
||||||
|
+ const std::string& process_type) {
|
||||||
|
+ return false;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+std::string CrashReporterClient::GetCrashServerURL() {
|
||||||
|
+ return std::string();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void CrashReporterClient::GetCrashOptionalArguments(
|
||||||
|
+ std::vector<std::string>* arguments) {
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#if defined(OS_WIN)
|
||||||
|
+base::string16 CrashReporterClient::GetCrashExternalHandler(
|
||||||
|
+ const base::string16& exe_dir) {
|
||||||
|
+ return exe_dir + L"\\crashpad_handler.exe";
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
int CrashReporterClient::GetAndroidMinidumpDescriptor() {
|
||||||
|
return 0;
|
||||||
|
@@ -165,9 +185,4 @@ bool CrashReporterClient::ShouldEnableBreakpadMicrodumps() {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-bool CrashReporterClient::EnableBreakpadForProcess(
|
||||||
|
- const std::string& process_type) {
|
||||||
|
- return false;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
} // namespace crash_reporter
|
||||||
|
diff --git components/crash/content/app/crash_reporter_client.h components/crash/content/app/crash_reporter_client.h
|
||||||
|
index 25ae505..349ee49 100644
|
||||||
|
--- components/crash/content/app/crash_reporter_client.h
|
||||||
|
+++ components/crash/content/app/crash_reporter_client.h
|
||||||
|
@@ -8,6 +8,7 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
+#include <vector>
|
||||||
|
|
||||||
|
#include "base/strings/string16.h"
|
||||||
|
#include "build/build_config.h"
|
||||||
|
@@ -176,6 +177,17 @@ class CrashReporterClient {
|
||||||
|
|
||||||
|
// Returns true if breakpad should run in the given process type.
|
||||||
|
virtual bool EnableBreakpadForProcess(const std::string& process_type);
|
||||||
|
+
|
||||||
|
+ // Returns the URL for submitting crash reports.
|
||||||
|
+ virtual std::string GetCrashServerURL();
|
||||||
|
+
|
||||||
|
+ // Populate |arguments| with additional optional arguments.
|
||||||
|
+ virtual void GetCrashOptionalArguments(std::vector<std::string>* arguments);
|
||||||
|
+
|
||||||
|
+#if defined(OS_WIN)
|
||||||
|
+ // Returns the absolute path to the external crash handler exe.
|
||||||
|
+ virtual base::string16 GetCrashExternalHandler(const base::string16& exe_dir);
|
||||||
|
+#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace crash_reporter
|
||||||
|
diff --git components/crash/content/app/crashpad_mac.mm components/crash/content/app/crashpad_mac.mm
|
||||||
|
index 7df66ea..f841aea 100644
|
||||||
|
--- components/crash/content/app/crashpad_mac.mm
|
||||||
|
+++ components/crash/content/app/crashpad_mac.mm
|
||||||
|
@@ -16,11 +16,14 @@
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/mac/bundle_locations.h"
|
||||||
|
#include "base/mac/foundation_util.h"
|
||||||
|
+#include "base/path_service.h"
|
||||||
|
#include "base/strings/string_number_conversions.h"
|
||||||
|
#include "base/strings/string_piece.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
|
#include "base/strings/sys_string_conversions.h"
|
||||||
|
#include "components/crash/content/app/crash_reporter_client.h"
|
||||||
|
+#include "components/crash/content/app/crash_switches.h"
|
||||||
|
+#include "content/public/common/content_paths.h"
|
||||||
|
#include "third_party/crashpad/crashpad/client/crash_report_database.h"
|
||||||
|
#include "third_party/crashpad/crashpad/client/crashpad_client.h"
|
||||||
|
#include "third_party/crashpad/crashpad/client/crashpad_info.h"
|
||||||
|
@@ -40,9 +43,10 @@
|
||||||
|
|
||||||
|
if (initial_client) {
|
||||||
|
@autoreleasepool {
|
||||||
|
- base::FilePath framework_bundle_path = base::mac::FrameworkBundlePath();
|
||||||
|
- base::FilePath handler_path =
|
||||||
|
- framework_bundle_path.Append("Helpers").Append("crashpad_handler");
|
||||||
|
+ // Use the same subprocess helper exe.
|
||||||
|
+ base::FilePath handler_path;
|
||||||
|
+ PathService::Get(content::CHILD_PROCESS_EXE, &handler_path);
|
||||||
|
+ DCHECK(!handler_path.empty());
|
||||||
|
|
||||||
|
// Is there a way to recover if this fails?
|
||||||
|
CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
|
||||||
|
@@ -54,7 +58,7 @@
|
||||||
|
// crash server won't have symbols for any other build types.
|
||||||
|
std::string url = "https://clients2.google.com/cr/report";
|
||||||
|
#else
|
||||||
|
- std::string url;
|
||||||
|
+ std::string url = crash_reporter_client->GetCrashServerURL();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::map<std::string, std::string> process_annotations;
|
||||||
|
@@ -90,6 +94,12 @@
|
||||||
|
"--reset-own-crash-exception-port-to-system-default");
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Since we're using the same subprocess helper exe we must specify the
|
||||||
|
+ // process type.
|
||||||
|
+ arguments.push_back(std::string("--type=") + switches::kCrashpadHandler);
|
||||||
|
+
|
||||||
|
+ crash_reporter_client->GetCrashOptionalArguments(&arguments);
|
||||||
|
+
|
||||||
|
crashpad::CrashpadClient crashpad_client;
|
||||||
|
bool result = crashpad_client.StartHandler(handler_path,
|
||||||
|
database_path,
|
||||||
|
diff --git components/crash/content/app/crashpad_win.cc components/crash/content/app/crashpad_win.cc
|
||||||
|
index a22af31..bc5086e 100644
|
||||||
|
--- components/crash/content/app/crashpad_win.cc
|
||||||
|
+++ components/crash/content/app/crashpad_win.cc
|
||||||
|
@@ -81,7 +81,7 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
|
||||||
|
#if defined(GOOGLE_CHROME_BUILD)
|
||||||
|
std::string url = "https://clients2.google.com/cr/report";
|
||||||
|
#else
|
||||||
|
- std::string url;
|
||||||
|
+ std::string url = crash_reporter_client->GetCrashServerURL();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Allow the crash server to be overridden for testing. If the variable
|
||||||
|
@@ -115,9 +115,12 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
|
||||||
|
arguments.push_back("/prefetch:7");
|
||||||
|
} else {
|
||||||
|
base::FilePath exe_dir = exe_file.DirName();
|
||||||
|
- exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe"));
|
||||||
|
+ exe_file = base::FilePath(
|
||||||
|
+ crash_reporter_client->GetCrashExternalHandler(exe_dir.value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
+ crash_reporter_client->GetCrashOptionalArguments(&arguments);
|
||||||
|
+
|
||||||
|
g_crashpad_client.Get().StartHandler(
|
||||||
|
exe_file, database_path, metrics_path, url, process_annotations,
|
||||||
|
arguments, false, false);
|
||||||
|
diff --git content/browser/frame_host/debug_urls.cc content/browser/frame_host/debug_urls.cc
|
||||||
|
index 2e61cc1..6b8b943 100644
|
||||||
|
--- content/browser/frame_host/debug_urls.cc
|
||||||
|
+++ content/browser/frame_host/debug_urls.cc
|
||||||
|
@@ -189,7 +189,9 @@ bool HandleDebugURL(const GURL& url, ui::PageTransition transition) {
|
||||||
|
cc::switches::kEnableGpuBenchmarking) &&
|
||||||
|
(PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED));
|
||||||
|
|
||||||
|
- if (!(transition & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) &&
|
||||||
|
+ // CEF does not use PAGE_TRANSITION_FROM_ADDRESS_BAR.
|
||||||
|
+ if (!(transition & (ui::PAGE_TRANSITION_TYPED ||
|
||||||
|
+ ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)) &&
|
||||||
|
!is_telemetry_navigation)
|
||||||
|
return false;
|
||||||
|
|
290
patch/patches/crashpad_tp_1995.patch
Normal file
290
patch/patches/crashpad_tp_1995.patch
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
diff --git crashpad/client/prune_crash_reports.cc crashpad/client/prune_crash_reports.cc
|
||||||
|
index 3aaaeee..d99fcb4 100644
|
||||||
|
--- crashpad/client/prune_crash_reports.cc
|
||||||
|
+++ crashpad/client/prune_crash_reports.cc
|
||||||
|
@@ -67,13 +67,19 @@ void PruneCrashReportDatabase(CrashReportDatabase* database,
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
-std::unique_ptr<PruneCondition> PruneCondition::GetDefault() {
|
||||||
|
+std::unique_ptr<PruneCondition> PruneCondition::GetDefault(
|
||||||
|
+ int max_size_in_mb,
|
||||||
|
+ int max_age_in_days) {
|
||||||
|
// DatabaseSizePruneCondition must be the LHS so that it is always evaluated,
|
||||||
|
// due to the short-circuting behavior of BinaryPruneCondition.
|
||||||
|
+ if (max_size_in_mb <= 0)
|
||||||
|
+ max_size_in_mb = 128;
|
||||||
|
+ if (max_age_in_days <= 0)
|
||||||
|
+ max_age_in_days = 365;
|
||||||
|
return base::WrapUnique(
|
||||||
|
new BinaryPruneCondition(BinaryPruneCondition::OR,
|
||||||
|
- new DatabaseSizePruneCondition(1024 * 128),
|
||||||
|
- new AgePruneCondition(365)));
|
||||||
|
+ new DatabaseSizePruneCondition(max_size_in_mb),
|
||||||
|
+ new AgePruneCondition(max_age_in_days)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const time_t kSecondsInDay = 60 * 60 * 24;
|
||||||
|
diff --git crashpad/client/prune_crash_reports.h crashpad/client/prune_crash_reports.h
|
||||||
|
index b66e9349..86d1f15 100644
|
||||||
|
--- crashpad/client/prune_crash_reports.h
|
||||||
|
+++ crashpad/client/prune_crash_reports.h
|
||||||
|
@@ -57,7 +57,8 @@ class PruneCondition {
|
||||||
|
//! of 128 MB.
|
||||||
|
//!
|
||||||
|
//! \return A PruneCondition for use with PruneCrashReportDatabase().
|
||||||
|
- static std::unique_ptr<PruneCondition> GetDefault();
|
||||||
|
+ static std::unique_ptr<PruneCondition> GetDefault(int max_size_in_mb,
|
||||||
|
+ int max_age_in_days);
|
||||||
|
|
||||||
|
virtual ~PruneCondition() {}
|
||||||
|
|
||||||
|
diff --git crashpad/client/settings.cc crashpad/client/settings.cc
|
||||||
|
index d018e37f..47d8110 100644
|
||||||
|
--- crashpad/client/settings.cc
|
||||||
|
+++ crashpad/client/settings.cc
|
||||||
|
@@ -38,7 +38,7 @@ void ScopedLockedFileHandleTraits::Free(FileHandle handle) {
|
||||||
|
|
||||||
|
struct Settings::Data {
|
||||||
|
static const uint32_t kSettingsMagic = 'CPds';
|
||||||
|
- static const uint32_t kSettingsVersion = 1;
|
||||||
|
+ static const uint32_t kSettingsVersion = 2;
|
||||||
|
|
||||||
|
enum Options : uint32_t {
|
||||||
|
kUploadsEnabled = 1 << 0,
|
||||||
|
@@ -49,6 +49,9 @@ struct Settings::Data {
|
||||||
|
options(0),
|
||||||
|
padding_0(0),
|
||||||
|
last_upload_attempt_time(0),
|
||||||
|
+ next_upload_attempt_time(0),
|
||||||
|
+ backoff_step(0),
|
||||||
|
+ padding_1(0),
|
||||||
|
client_id() {}
|
||||||
|
|
||||||
|
uint32_t magic;
|
||||||
|
@@ -56,6 +59,9 @@ struct Settings::Data {
|
||||||
|
uint32_t options;
|
||||||
|
uint32_t padding_0;
|
||||||
|
uint64_t last_upload_attempt_time; // time_t
|
||||||
|
+ uint64_t next_upload_attempt_time; // time_t
|
||||||
|
+ uint32_t backoff_step;
|
||||||
|
+ uint32_t padding_1;
|
||||||
|
UUID client_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -141,6 +147,56 @@ bool Settings::SetLastUploadAttemptTime(time_t time) {
|
||||||
|
return WriteSettings(handle.get(), settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
+bool Settings::GetNextUploadAttemptTime(time_t* time) {
|
||||||
|
+ DCHECK(initialized_.is_valid());
|
||||||
|
+
|
||||||
|
+ Data settings;
|
||||||
|
+ if (!OpenAndReadSettings(&settings))
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ *time = InRangeCast<time_t>(settings.next_upload_attempt_time,
|
||||||
|
+ std::numeric_limits<time_t>::max());
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool Settings::SetNextUploadAttemptTime(time_t time) {
|
||||||
|
+ DCHECK(initialized_.is_valid());
|
||||||
|
+
|
||||||
|
+ Data settings;
|
||||||
|
+ ScopedLockedFileHandle handle = OpenForWritingAndReadSettings(&settings);
|
||||||
|
+ if (!handle.is_valid())
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ settings.next_upload_attempt_time = InRangeCast<uint64_t>(time, 0);
|
||||||
|
+
|
||||||
|
+ return WriteSettings(handle.get(), settings);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool Settings::GetBackoffStep(int* step) {
|
||||||
|
+ DCHECK(initialized_.is_valid());
|
||||||
|
+
|
||||||
|
+ Data settings;
|
||||||
|
+ if (!OpenAndReadSettings(&settings))
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ *step = InRangeCast<int>(settings.backoff_step,
|
||||||
|
+ std::numeric_limits<int>::max());
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool Settings::SetBackoffStep(int step) {
|
||||||
|
+ DCHECK(initialized_.is_valid());
|
||||||
|
+
|
||||||
|
+ Data settings;
|
||||||
|
+ ScopedLockedFileHandle handle = OpenForWritingAndReadSettings(&settings);
|
||||||
|
+ if (!handle.is_valid())
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ settings.backoff_step = InRangeCast<uint32_t>(step, 0);
|
||||||
|
+
|
||||||
|
+ return WriteSettings(handle.get(), settings);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
// static
|
||||||
|
Settings::ScopedLockedFileHandle Settings::MakeScopedLockedFileHandle(
|
||||||
|
FileHandle file,
|
||||||
|
diff --git crashpad/client/settings.h crashpad/client/settings.h
|
||||||
|
index b64f74f..0c3c22e 100644
|
||||||
|
--- crashpad/client/settings.h
|
||||||
|
+++ crashpad/client/settings.h
|
||||||
|
@@ -102,6 +102,11 @@ class Settings {
|
||||||
|
//! error logged.
|
||||||
|
bool SetLastUploadAttemptTime(time_t time);
|
||||||
|
|
||||||
|
+ bool GetNextUploadAttemptTime(time_t* time);
|
||||||
|
+ bool SetNextUploadAttemptTime(time_t time);
|
||||||
|
+ bool GetBackoffStep(int* step);
|
||||||
|
+ bool SetBackoffStep(int step);
|
||||||
|
+
|
||||||
|
private:
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
diff --git crashpad/handler/crash_report_upload_thread.h crashpad/handler/crash_report_upload_thread.h
|
||||||
|
index a9601d1..9517730 100644
|
||||||
|
--- crashpad/handler/crash_report_upload_thread.h
|
||||||
|
+++ crashpad/handler/crash_report_upload_thread.h
|
||||||
|
@@ -76,7 +76,7 @@ class CrashReportUploadThread : public WorkerThread::Delegate {
|
||||||
|
//! This method may be called from any thread.
|
||||||
|
void ReportPending();
|
||||||
|
|
||||||
|
- private:
|
||||||
|
+ protected:
|
||||||
|
//! \brief The result code from UploadReport().
|
||||||
|
enum class UploadResult {
|
||||||
|
//! \brief The crash report was uploaded successfully.
|
||||||
|
@@ -99,7 +99,7 @@ class CrashReportUploadThread : public WorkerThread::Delegate {
|
||||||
|
|
||||||
|
//! \brief Obtains all pending reports from the database, and calls
|
||||||
|
//! ProcessPendingReport() to process each one.
|
||||||
|
- void ProcessPendingReports();
|
||||||
|
+ virtual void ProcessPendingReports();
|
||||||
|
|
||||||
|
//! \brief Processes a single pending report from the database.
|
||||||
|
//!
|
||||||
|
@@ -113,7 +113,7 @@ class CrashReportUploadThread : public WorkerThread::Delegate {
|
||||||
|
//! remain in the “pending” state. If the upload fails and no more retries are
|
||||||
|
//! desired, or report upload is disabled, it will be marked as “completed” in
|
||||||
|
//! the database without ever having been uploaded.
|
||||||
|
- void ProcessPendingReport(const CrashReportDatabase::Report& report);
|
||||||
|
+ virtual void ProcessPendingReport(const CrashReportDatabase::Report& report);
|
||||||
|
|
||||||
|
//! \brief Attempts to upload a crash report.
|
||||||
|
//!
|
||||||
|
diff --git crashpad/handler/handler_main.cc crashpad/handler/handler_main.cc
|
||||||
|
index 29c5ddc..7a6bad7 100644
|
||||||
|
--- crashpad/handler/handler_main.cc
|
||||||
|
+++ crashpad/handler/handler_main.cc
|
||||||
|
@@ -29,8 +29,10 @@
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/metrics/persistent_histogram_allocator.h"
|
||||||
|
#include "base/scoped_generic.h"
|
||||||
|
+#include "base/strings/string_number_conversions.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
|
#include "build/build_config.h"
|
||||||
|
+#include "cef/libcef/features/features.h"
|
||||||
|
#include "client/crash_report_database.h"
|
||||||
|
#include "client/crashpad_client.h"
|
||||||
|
#include "client/prune_crash_reports.h"
|
||||||
|
@@ -62,6 +64,10 @@
|
||||||
|
#include "util/win/initial_client_data.h"
|
||||||
|
#endif // OS_MACOSX
|
||||||
|
|
||||||
|
+#if BUILDFLAG(ENABLE_CEF)
|
||||||
|
+#include "cef/libcef/common/cef_crash_report_upload_thread.h"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
@@ -168,6 +174,9 @@ int HandlerMain(int argc, char* argv[]) {
|
||||||
|
kOptionPipeName,
|
||||||
|
#endif // OS_MACOSX
|
||||||
|
kOptionURL,
|
||||||
|
+ kOptionMaxUploads,
|
||||||
|
+ kOptionMaxDatabaseSize,
|
||||||
|
+ kOptionMaxDatabaseAge,
|
||||||
|
|
||||||
|
// Standard options.
|
||||||
|
kOptionHelp = -2,
|
||||||
|
@@ -188,11 +197,17 @@ int HandlerMain(int argc, char* argv[]) {
|
||||||
|
InitialClientData initial_client_data;
|
||||||
|
#endif // OS_MACOSX
|
||||||
|
bool rate_limit;
|
||||||
|
+ int max_uploads;
|
||||||
|
+ int max_database_size;
|
||||||
|
+ int max_database_age;
|
||||||
|
} options = {};
|
||||||
|
#if defined(OS_MACOSX)
|
||||||
|
options.handshake_fd = -1;
|
||||||
|
#endif
|
||||||
|
options.rate_limit = true;
|
||||||
|
+ options.max_uploads = 0;
|
||||||
|
+ options.max_database_size = 0;
|
||||||
|
+ options.max_database_age = 0;
|
||||||
|
|
||||||
|
const option long_options[] = {
|
||||||
|
{"annotation", required_argument, nullptr, kOptionAnnotation},
|
||||||
|
@@ -222,6 +237,9 @@ int HandlerMain(int argc, char* argv[]) {
|
||||||
|
{"url", required_argument, nullptr, kOptionURL},
|
||||||
|
{"help", no_argument, nullptr, kOptionHelp},
|
||||||
|
{"version", no_argument, nullptr, kOptionVersion},
|
||||||
|
+ {"max-uploads", required_argument, nullptr, kOptionMaxUploads},
|
||||||
|
+ {"max-db-size", required_argument, nullptr, kOptionMaxDatabaseSize},
|
||||||
|
+ {"max-db-age", required_argument, nullptr, kOptionMaxDatabaseAge},
|
||||||
|
{nullptr, 0, nullptr, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -293,6 +311,27 @@ int HandlerMain(int argc, char* argv[]) {
|
||||||
|
options.url = optarg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
+ case kOptionMaxUploads: {
|
||||||
|
+ if (base::StringToInt(optarg, &options.max_uploads)) {
|
||||||
|
+ if (options.max_uploads < 0)
|
||||||
|
+ options.max_uploads = 0;
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ case kOptionMaxDatabaseSize: {
|
||||||
|
+ if (base::StringToInt(optarg, &options.max_database_size)) {
|
||||||
|
+ if (options.max_database_size < 0)
|
||||||
|
+ options.max_database_size = 0;
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ case kOptionMaxDatabaseAge: {
|
||||||
|
+ if (base::StringToInt(optarg, &options.max_database_age)) {
|
||||||
|
+ if (options.max_database_age < 0)
|
||||||
|
+ options.max_database_age = 0;
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
case kOptionHelp: {
|
||||||
|
Usage(me);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
@@ -425,12 +464,18 @@ int HandlerMain(int argc, char* argv[]) {
|
||||||
|
// TODO(scottmg): options.rate_limit should be removed when we have a
|
||||||
|
// configurable database setting to control upload limiting.
|
||||||
|
// See https://crashpad.chromium.org/bug/23.
|
||||||
|
+#if BUILDFLAG(ENABLE_CEF)
|
||||||
|
+ CefCrashReportUploadThread upload_thread(
|
||||||
|
+ database.get(), options.url, options.rate_limit, options.max_uploads);
|
||||||
|
+#else
|
||||||
|
CrashReportUploadThread upload_thread(
|
||||||
|
database.get(), options.url, options.rate_limit);
|
||||||
|
+#endif
|
||||||
|
upload_thread.Start();
|
||||||
|
|
||||||
|
PruneCrashReportThread prune_thread(database.get(),
|
||||||
|
- PruneCondition::GetDefault());
|
||||||
|
+ PruneCondition::GetDefault(options.max_database_size,
|
||||||
|
+ options.max_database_age));
|
||||||
|
prune_thread.Start();
|
||||||
|
|
||||||
|
CrashReportExceptionHandler exception_handler(
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include "tests/shared/browser/client_app_browser.h"
|
#include "tests/shared/browser/client_app_browser.h"
|
||||||
|
|
||||||
|
#include "tests/cefclient/browser/client_browser.h"
|
||||||
|
|
||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
#include "tests/cefclient/browser/print_handler_gtk.h"
|
#include "tests/cefclient/browser/print_handler_gtk.h"
|
||||||
#endif
|
#endif
|
||||||
@ -12,6 +14,7 @@ namespace client {
|
|||||||
|
|
||||||
// static
|
// static
|
||||||
void ClientAppBrowser::CreateDelegates(DelegateSet& delegates) {
|
void ClientAppBrowser::CreateDelegates(DelegateSet& delegates) {
|
||||||
|
browser::CreateDelegates(delegates);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
40
tests/cefclient/browser/client_browser.cc
Normal file
40
tests/cefclient/browser/client_browser.cc
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (c) 2016 The Chromium Embedded Framework 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 "tests/cefclient/browser/client_browser.h"
|
||||||
|
|
||||||
|
#include "include/cef_crash_util.h"
|
||||||
|
|
||||||
|
namespace client {
|
||||||
|
namespace browser {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ClientBrowserDelegate : public ClientAppBrowser::Delegate {
|
||||||
|
public:
|
||||||
|
ClientBrowserDelegate() {}
|
||||||
|
|
||||||
|
void OnContextInitialized(CefRefPtr<ClientAppBrowser> app) OVERRIDE {
|
||||||
|
if (CefCrashReportingEnabled()) {
|
||||||
|
// Set some crash keys for testing purposes. Keys must be defined in the
|
||||||
|
// "crash_reporter.cfg" file. See cef_crash_util.h for details.
|
||||||
|
CefSetCrashKeyValue("testkey1", "value1_browser");
|
||||||
|
CefSetCrashKeyValue("testkey2", "value2_browser");
|
||||||
|
CefSetCrashKeyValue("testkey3", "value3_browser");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(ClientBrowserDelegate);
|
||||||
|
IMPLEMENT_REFCOUNTING(ClientBrowserDelegate);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void CreateDelegates(ClientAppBrowser::DelegateSet& delegates) {
|
||||||
|
delegates.insert(new ClientBrowserDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace browser
|
||||||
|
} // namespace client
|
21
tests/cefclient/browser/client_browser.h
Normal file
21
tests/cefclient/browser/client_browser.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
|
||||||
|
// reserved. Use of this source code is governed by a BSD-style license that
|
||||||
|
// can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_BROWSER_H_
|
||||||
|
#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_BROWSER_H_
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "include/cef_base.h"
|
||||||
|
#include "tests/shared/browser/client_app_browser.h"
|
||||||
|
|
||||||
|
namespace client {
|
||||||
|
namespace browser {
|
||||||
|
|
||||||
|
// Create the browser delegate. Called from client_app_delegates_browser.cc.
|
||||||
|
void CreateDelegates(ClientAppBrowser::DelegateSet& delegates);
|
||||||
|
|
||||||
|
} // namespace browser
|
||||||
|
} // namespace client
|
||||||
|
|
||||||
|
#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_BROWSER_H_
|
@ -7,6 +7,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "include/cef_crash_util.h"
|
||||||
#include "include/cef_dom.h"
|
#include "include/cef_dom.h"
|
||||||
#include "include/wrapper/cef_helpers.h"
|
#include "include/wrapper/cef_helpers.h"
|
||||||
#include "include/wrapper/cef_message_router.h"
|
#include "include/wrapper/cef_message_router.h"
|
||||||
@ -25,30 +26,42 @@ class ClientRenderDelegate : public ClientAppRenderer::Delegate {
|
|||||||
: last_node_is_editable_(false) {
|
: last_node_is_editable_(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app) OVERRIDE {
|
void OnRenderThreadCreated(
|
||||||
|
CefRefPtr<ClientAppRenderer> app,
|
||||||
|
CefRefPtr<CefListValue> extra_info) OVERRIDE {
|
||||||
|
if (CefCrashReportingEnabled()) {
|
||||||
|
// Set some crash keys for testing purposes. Keys must be defined in the
|
||||||
|
// "crash_reporter.cfg" file. See cef_crash_util.h for details.
|
||||||
|
CefSetCrashKeyValue("testkey1", "value1_renderer");
|
||||||
|
CefSetCrashKeyValue("testkey2", "value2_renderer");
|
||||||
|
CefSetCrashKeyValue("testkey3", "value3_renderer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app) OVERRIDE {
|
||||||
// Create the renderer-side router for query handling.
|
// Create the renderer-side router for query handling.
|
||||||
CefMessageRouterConfig config;
|
CefMessageRouterConfig config;
|
||||||
message_router_ = CefMessageRouterRendererSide::Create(config);
|
message_router_ = CefMessageRouterRendererSide::Create(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnContextCreated(CefRefPtr<ClientAppRenderer> app,
|
void OnContextCreated(CefRefPtr<ClientAppRenderer> app,
|
||||||
CefRefPtr<CefBrowser> browser,
|
CefRefPtr<CefBrowser> browser,
|
||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
CefRefPtr<CefV8Context> context) OVERRIDE {
|
CefRefPtr<CefV8Context> context) OVERRIDE {
|
||||||
message_router_->OnContextCreated(browser, frame, context);
|
message_router_->OnContextCreated(browser, frame, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnContextReleased(CefRefPtr<ClientAppRenderer> app,
|
void OnContextReleased(CefRefPtr<ClientAppRenderer> app,
|
||||||
CefRefPtr<CefBrowser> browser,
|
CefRefPtr<CefBrowser> browser,
|
||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
CefRefPtr<CefV8Context> context) OVERRIDE {
|
CefRefPtr<CefV8Context> context) OVERRIDE {
|
||||||
message_router_->OnContextReleased(browser, frame, context);
|
message_router_->OnContextReleased(browser, frame, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnFocusedNodeChanged(CefRefPtr<ClientAppRenderer> app,
|
void OnFocusedNodeChanged(CefRefPtr<ClientAppRenderer> app,
|
||||||
CefRefPtr<CefBrowser> browser,
|
CefRefPtr<CefBrowser> browser,
|
||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
CefRefPtr<CefDOMNode> node) OVERRIDE {
|
CefRefPtr<CefDOMNode> node) OVERRIDE {
|
||||||
bool is_editable = (node.get() && node->IsEditable());
|
bool is_editable = (node.get() && node->IsEditable());
|
||||||
if (is_editable != last_node_is_editable_) {
|
if (is_editable != last_node_is_editable_) {
|
||||||
// Notify the browser of the change in focused element type.
|
// Notify the browser of the change in focused element type.
|
||||||
@ -60,7 +73,7 @@ class ClientRenderDelegate : public ClientAppRenderer::Delegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool OnProcessMessageReceived(
|
bool OnProcessMessageReceived(
|
||||||
CefRefPtr<ClientAppRenderer> app,
|
CefRefPtr<ClientAppRenderer> app,
|
||||||
CefRefPtr<CefBrowser> browser,
|
CefRefPtr<CefBrowser> browser,
|
||||||
CefProcessId source_process,
|
CefProcessId source_process,
|
||||||
@ -75,6 +88,7 @@ class ClientRenderDelegate : public ClientAppRenderer::Delegate {
|
|||||||
// Handles the renderer side of query routing.
|
// Handles the renderer side of query routing.
|
||||||
CefRefPtr<CefMessageRouterRendererSide> message_router_;
|
CefRefPtr<CefMessageRouterRendererSide> message_router_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(ClientRenderDelegate);
|
||||||
IMPLEMENT_REFCOUNTING(ClientRenderDelegate);
|
IMPLEMENT_REFCOUNTING(ClientRenderDelegate);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
235
tools/crash_server.py
Normal file
235
tools/crash_server.py
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright 2017 The Chromium Embedded Framework Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be found
|
||||||
|
# in the LICENSE file.
|
||||||
|
|
||||||
|
"""
|
||||||
|
This script implements a simple HTTP server for receiving crash report uploads
|
||||||
|
from a Breakpad/Crashpad client (any CEF-based application). This script is
|
||||||
|
intended for testing purposes only. An HTTPS server and a system such as Socorro
|
||||||
|
(https://wiki.mozilla.org/Socorro) should be used when uploading crash reports
|
||||||
|
from production applications.
|
||||||
|
|
||||||
|
Usage of this script is as follows:
|
||||||
|
|
||||||
|
1. Run this script from the command-line. The first argument is the server port
|
||||||
|
number and the second argument is the directory where uploaded report
|
||||||
|
information will be saved:
|
||||||
|
|
||||||
|
> python crash_server.py 8080 /path/to/dumps
|
||||||
|
|
||||||
|
2. Create a "crash_reporter.cfg" file at the required platform-specific
|
||||||
|
location. On Windows and Linux this file must be placed next to the main
|
||||||
|
application executable. On macOS this file must be placed in the top-level
|
||||||
|
app bundle Resources directory (e.g. "<appname>.app/Contents/Resources"). At
|
||||||
|
a minimum it must contain a "ServerURL=http://localhost:8080" line under the
|
||||||
|
"[Config]" section (make sure the port number matches the value specified in
|
||||||
|
step 1). See comments in include/cef_crash_util.h for a complete
|
||||||
|
specification of this file.
|
||||||
|
|
||||||
|
Example file contents:
|
||||||
|
|
||||||
|
[Config]
|
||||||
|
ServerURL=http://localhost:8080
|
||||||
|
# Disable rate limiting so that all crashes are uploaded.
|
||||||
|
RateLimitEnabled=false
|
||||||
|
MaxUploadsPerDay=0
|
||||||
|
|
||||||
|
[CrashKeys]
|
||||||
|
# The cefclient sample application sets these values (see step 5 below).
|
||||||
|
testkey1=small
|
||||||
|
testkey2=medium
|
||||||
|
testkey3=large
|
||||||
|
|
||||||
|
3. Load one of the following URLs in the CEF-based application to cause a crash:
|
||||||
|
|
||||||
|
Main (browser) process crash: chrome://inducebrowsercrashforrealz
|
||||||
|
Renderer process crash: chrome://crash
|
||||||
|
GPU process crash: chrome://gpucrash
|
||||||
|
|
||||||
|
4. When this script successfully receives a crash report upload you will see
|
||||||
|
console output like the following:
|
||||||
|
|
||||||
|
01/10/2017 12:31:23: Dump <id>
|
||||||
|
|
||||||
|
The "<id>" value is a 16 digit hexadecimal string that uniquely identifies
|
||||||
|
the dump. Crash dumps and metadata (product state, command-line flags, crash
|
||||||
|
keys, etc.) will be written to the "<id>.dmp" and "<id>.json" files
|
||||||
|
underneath the directory specified in step 1.
|
||||||
|
|
||||||
|
On Linux Breakpad uses the wget utility to upload crash dumps, so make sure
|
||||||
|
that utility is installed. If the crash is handled correctly then you should
|
||||||
|
see console output like the following when the client uploads a crash dump:
|
||||||
|
|
||||||
|
--2017-01-10 12:31:22-- http://localhost:8080/
|
||||||
|
Resolving localhost (localhost)... 127.0.0.1
|
||||||
|
Connecting to localhost (localhost)|127.0.0.1|:8080... connected.
|
||||||
|
HTTP request sent, awaiting response... 200 OK
|
||||||
|
Length: unspecified [text/html]
|
||||||
|
Saving to: '/dev/fd/3'
|
||||||
|
Crash dump id: <id>
|
||||||
|
|
||||||
|
On macOS when uploading a crash report to this script over HTTP you may
|
||||||
|
receive an error like the following:
|
||||||
|
|
||||||
|
"Transport security has blocked a cleartext HTTP (http://) resource load
|
||||||
|
since it is insecure. Temporary exceptions can be configured via your app's
|
||||||
|
Info.plist file."
|
||||||
|
|
||||||
|
You can work around this error by adding the following key to the Helper app
|
||||||
|
Info.plist file (e.g. "<appname>.app/Contents/Frameworks/
|
||||||
|
<appname> Helper.app/Contents/Info.plist"):
|
||||||
|
|
||||||
|
<key>NSAppTransportSecurity</key>
|
||||||
|
<dict>
|
||||||
|
<!--Allow all connections (for testing only!)-->
|
||||||
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
|
||||||
|
5. The cefclient sample application sets test crash key values in the browser
|
||||||
|
and renderer processes. To work properly these values must also be defined
|
||||||
|
in the "[CrashKeys]" section of "crash_reporter.cfg" as shown above.
|
||||||
|
|
||||||
|
In tests/cefclient/browser/client_browser.cc (browser process):
|
||||||
|
|
||||||
|
CefSetCrashKeyValue("testkey1", "value1_browser");
|
||||||
|
CefSetCrashKeyValue("testkey2", "value2_browser");
|
||||||
|
CefSetCrashKeyValue("testkey3", "value3_browser");
|
||||||
|
|
||||||
|
In tests/cefclient/renderer/client_renderer.cc (renderer process):
|
||||||
|
|
||||||
|
CefSetCrashKeyValue("testkey1", "value1_renderer");
|
||||||
|
CefSetCrashKeyValue("testkey2", "value2_renderer");
|
||||||
|
CefSetCrashKeyValue("testkey3", "value3_renderer");
|
||||||
|
|
||||||
|
When crashing the browser or renderer processes with cefclient you should
|
||||||
|
verify that the test crash key values are included in the metadata
|
||||||
|
("<id>.json") file. Some values may be chunked as described in
|
||||||
|
include/cef_crash_util.h.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||||
|
import cgi
|
||||||
|
import cStringIO
|
||||||
|
import datetime
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import uuid
|
||||||
|
import zlib
|
||||||
|
|
||||||
|
def print_msg(msg):
|
||||||
|
""" Write |msg| to stdout and flush. """
|
||||||
|
timestr = datetime.datetime.now().strftime("%m/%d/%Y %H:%M:%S")
|
||||||
|
sys.stdout.write("%s: %s\n" % (timestr, msg))
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
# Key identifying the minidump file.
|
||||||
|
minidump_key = 'upload_file_minidump'
|
||||||
|
|
||||||
|
class CrashHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||||
|
def __init__(self, dump_directory, *args):
|
||||||
|
self._dump_directory = dump_directory
|
||||||
|
BaseHTTPRequestHandler.__init__(self, *args)
|
||||||
|
|
||||||
|
def _send_default_response_headers(self):
|
||||||
|
""" Send default response headers. """
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'text/html')
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def _parse_post_data(self):
|
||||||
|
""" Returns a cgi.FieldStorage object for this request or None if this is
|
||||||
|
not a POST request. """
|
||||||
|
if self.command != 'POST':
|
||||||
|
return None
|
||||||
|
return cgi.FieldStorage(
|
||||||
|
fp = self.rfile,
|
||||||
|
headers = self.headers,
|
||||||
|
environ = {
|
||||||
|
'REQUEST_METHOD': 'POST',
|
||||||
|
'CONTENT_TYPE': self.headers['Content-Type'],
|
||||||
|
})
|
||||||
|
|
||||||
|
def _create_new_dump_id(self):
|
||||||
|
""" Breakpad requires a 16 digit hexadecimal dump ID. """
|
||||||
|
return str(uuid.uuid4().get_hex().upper()[0:16])
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
""" Default empty implementation for handling GET requests. """
|
||||||
|
self._send_default_response_headers()
|
||||||
|
self.wfile.write("<html><body><h1>GET!</h1></body></html>")
|
||||||
|
|
||||||
|
def do_HEAD(self):
|
||||||
|
""" Default empty implementation for handling HEAD requests. """
|
||||||
|
self._send_default_response_headers()
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
""" Handle a multi-part POST request submitted by Breakpad/Crashpad. """
|
||||||
|
self._send_default_response_headers()
|
||||||
|
|
||||||
|
# Create a unique ID for the dump.
|
||||||
|
dump_id = self._create_new_dump_id()
|
||||||
|
|
||||||
|
# Return the unique ID to the caller.
|
||||||
|
self.wfile.write(dump_id)
|
||||||
|
|
||||||
|
dmp_stream = None
|
||||||
|
metadata = {}
|
||||||
|
|
||||||
|
# Breakpad on Linux sends gzipped request contents.
|
||||||
|
if 'Content-Encoding' in self.headers and self.headers['Content-Encoding'] == 'gzip':
|
||||||
|
print_msg('Decompressing gzipped request')
|
||||||
|
self.rfile = cStringIO.StringIO(zlib.decompress(self.rfile.read(), 16+zlib.MAX_WBITS))
|
||||||
|
|
||||||
|
# Parse the multi-part request.
|
||||||
|
form_data = self._parse_post_data()
|
||||||
|
for key in form_data.keys():
|
||||||
|
if key == minidump_key and form_data[minidump_key].file:
|
||||||
|
dmp_stream = form_data[minidump_key].file
|
||||||
|
else:
|
||||||
|
metadata[key] = form_data[key].value
|
||||||
|
|
||||||
|
if dmp_stream is None:
|
||||||
|
# Exit early if the request is invalid.
|
||||||
|
print_msg('Invalid dump %s' % dump_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
print_msg('Dump %s' % dump_id)
|
||||||
|
|
||||||
|
# Write the minidump to file.
|
||||||
|
dump_file = os.path.join(self._dump_directory, dump_id + '.dmp')
|
||||||
|
with open(dump_file, 'wb') as fp:
|
||||||
|
shutil.copyfileobj(dmp_stream, fp)
|
||||||
|
|
||||||
|
# Write the metadata to file.
|
||||||
|
meta_file = os.path.join(self._dump_directory, dump_id + '.json')
|
||||||
|
with open(meta_file, 'w') as fp:
|
||||||
|
json.dump(metadata, fp)
|
||||||
|
|
||||||
|
def HandleRequestsUsing(dump_store):
|
||||||
|
return lambda *args: CrashHTTPRequestHandler(dump_directory, *args)
|
||||||
|
|
||||||
|
def RunCrashServer(port, dump_directory):
|
||||||
|
""" Run the crash handler HTTP server. """
|
||||||
|
httpd = HTTPServer(('', port), HandleRequestsUsing(dump_directory))
|
||||||
|
print_msg('Starting httpd on port %d' % port)
|
||||||
|
httpd.serve_forever()
|
||||||
|
|
||||||
|
# Program entry point.
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print 'Usage: %s <port> <dump_directory>' % os.path.basename(sys.argv[0])
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Create the dump directory if necessary.
|
||||||
|
dump_directory = sys.argv[2]
|
||||||
|
if not os.path.exists(dump_directory):
|
||||||
|
os.makedirs(dump_directory)
|
||||||
|
if not os.path.isdir(dump_directory):
|
||||||
|
raise Exception('Directory does not exist: %s' % dump_directory)
|
||||||
|
|
||||||
|
RunCrashServer(int(sys.argv[1]), dump_directory)
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user