summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-26 14:40:22 +0000
committermad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-26 14:40:22 +0000
commitc215cc0447d7a86964dd82bec54e91e01c0c6d0b (patch)
tree11b8923075c2790d4ca0bf4bd027edfb6fc09caa
parent9a3b349b671809ce7d790a6e0218689cabb7d9b2 (diff)
downloadchromium_src-c215cc0447d7a86964dd82bec54e91e01c0c6d0b.zip
chromium_src-c215cc0447d7a86964dd82bec54e91e01c0c6d0b.tar.gz
chromium_src-c215cc0447d7a86964dd82bec54e91e01c0c6d0b.tar.bz2
Add experiments info to crash dumps.
BUG=None TEST=Make sure that the crash dumps are correctly generated and contain experiments information when appropriate. Review URL: http://codereview.chromium.org/9432033 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@128910 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/breakpad_field_trial_win.cc102
-rw-r--r--chrome/app/breakpad_field_trial_win.h11
-rw-r--r--chrome/app/breakpad_unittest_win.cc89
-rw-r--r--chrome/app/breakpad_win.cc80
-rw-r--r--chrome/app/breakpad_win.h27
-rw-r--r--chrome/app/run_all_unittests.cc9
-rw-r--r--chrome/browser/metrics/field_trial_synchronizer.cc8
-rw-r--r--chrome/chrome_exe.gypi2
-rw-r--r--chrome/chrome_tests.gypi77
-rw-r--r--chrome/common/child_process_logging.h12
-rw-r--r--chrome/common/child_process_logging_mac.mm9
-rw-r--r--chrome/common/child_process_logging_posix.cc9
-rw-r--r--chrome/common/child_process_logging_win.cc38
-rw-r--r--chrome/renderer/chrome_render_process_observer.cc6
14 files changed, 457 insertions, 22 deletions
diff --git a/chrome/app/breakpad_field_trial_win.cc b/chrome/app/breakpad_field_trial_win.cc
new file mode 100644
index 0000000..7a7825d
--- /dev/null
+++ b/chrome/app/breakpad_field_trial_win.cc
@@ -0,0 +1,102 @@
+// Copyright (c) 2012 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 "chrome/app/breakpad_field_trial_win.h"
+
+#include "base/lazy_instance.h"
+#include "base/metrics/field_trial.h"
+#include "base/string_util.h"
+#include "base/string16.h"
+#include "base/stringprintf.h"
+#include "breakpad/src/client/windows/common/ipc_protocol.h"
+#include "chrome/app/breakpad_win.h"
+#include "chrome/common/child_process_logging.h"
+
+namespace {
+
+// Use this wrapper to be able to pass in the EmptyString to the constructor.
+// We could also use a traits, but we would still need a class, so...
+class FieldTrialListWrapper : base::FieldTrialList {
+ public:
+ FieldTrialListWrapper() : base::FieldTrialList(EmptyString()) {}
+};
+
+base::LazyInstance<FieldTrialListWrapper> g_field_trial_list =
+ LAZY_INSTANCE_INITIALIZER;
+
+}
+
+extern "C" void __declspec(dllexport) __cdecl InitExperimentList(
+ const std::string& state) {
+ // Make sure the global instance is created.
+ g_field_trial_list.Pointer();
+ base::FieldTrialList::CreateTrialsInChildProcess(state);
+ UpdateExperiments();
+}
+
+extern "C" void __declspec(dllexport) __cdecl AddFieldTrialGroup(
+ const std::string& field_trial_name, const std::string& group_name) {
+ base::FieldTrialList::CreateFieldTrial(field_trial_name, group_name);
+ // TODO(mad): Find a way to just add the |field_trial_name| and |group_name|
+ // instead of starting over each time.
+ UpdateExperiments();
+}
+
+void UpdateExperiments() {
+ // Make sure we were initialized before we start writing data
+ if (breakpad_win::g_experiment_chunks_offset == 0)
+ return;
+
+ std::vector<base::FieldTrial::NameGroupId> name_group_ids;
+ base::FieldTrialList::GetFieldTrialNameGroupIds(&name_group_ids);
+
+ std::vector<string16> experiment_strings(name_group_ids.size());
+ for (size_t i = 0; i < name_group_ids.size(); ++i) {
+ experiment_strings[i] = base::StringPrintf(
+ L"%x-%x", name_group_ids[i].name, name_group_ids[i].group);
+ }
+
+ size_t num_chunks = 0;
+ size_t current_experiment = 0;
+ string16 current_chunk(google_breakpad::CustomInfoEntry::kValueMaxLength, 0);
+ while (current_experiment < experiment_strings.size() &&
+ num_chunks < kMaxReportedExperimentChunks) {
+ // Check if we have enough room to add another experiment to the current
+ // chunk string. If not, we commit the current chunk string and start over.
+ if (current_chunk.size() + experiment_strings[current_experiment].size() >
+ google_breakpad::CustomInfoEntry::kValueMaxLength) {
+ base::wcslcpy(
+ (*breakpad_win::g_custom_entries)[
+ breakpad_win::g_experiment_chunks_offset + num_chunks].value,
+ current_chunk.c_str(),
+ current_chunk.size() + 1); // This must include the NULL termination.
+ ++num_chunks;
+ current_chunk = experiment_strings[current_experiment];
+ } else {
+ if (!current_chunk.empty())
+ current_chunk += L",";
+ current_chunk += experiment_strings[current_experiment];
+ }
+ ++current_experiment;
+ }
+
+ // Commit the last chunk that didn't get big enough yet.
+ if (!current_chunk.empty() && num_chunks < kMaxReportedExperimentChunks) {
+ base::wcslcpy(
+ (*breakpad_win::g_custom_entries)[
+ breakpad_win::g_experiment_chunks_offset + num_chunks].value,
+ current_chunk.c_str(),
+ current_chunk.size() + 1); // This must include the NULL termination.
+ }
+
+ // Make note of the total number of experiments,
+ // even if it's > kMaxReportedExperimentChunks. This is useful when
+ // correlating stability with the number of experiments running
+ // simultaneously.
+ base::wcslcpy(
+ (*breakpad_win::g_custom_entries)[
+ breakpad_win::g_num_of_experiments_offset].value,
+ base::StringPrintf(L"%d", name_group_ids.size()).c_str(),
+ google_breakpad::CustomInfoEntry::kValueMaxLength);
+}
diff --git a/chrome/app/breakpad_field_trial_win.h b/chrome/app/breakpad_field_trial_win.h
new file mode 100644
index 0000000..5e3ef8d
--- /dev/null
+++ b/chrome/app/breakpad_field_trial_win.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 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.
+
+#ifndef CHROME_APP_BREAKPAD_FIELD_TRIAL_WIN_H_
+#define CHROME_APP_BREAKPAD_FIELD_TRIAL_WIN_H_
+#pragma once
+
+void UpdateExperiments();
+
+#endif // CHROME_APP_BREAKPAD_FIELD_TRIAL_WIN_H_
diff --git a/chrome/app/breakpad_unittest_win.cc b/chrome/app/breakpad_unittest_win.cc
new file mode 100644
index 0000000..b33bffb
--- /dev/null
+++ b/chrome/app/breakpad_unittest_win.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2012 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 <vector>
+
+#include "base/metrics/field_trial.h"
+#include "base/stringprintf.h"
+#include "breakpad/src/client/windows/common/ipc_protocol.h"
+#include "chrome/app/breakpad_field_trial_win.h"
+#include "chrome/app/breakpad_win.h"
+#include "chrome/common/child_process_logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using breakpad_win::g_custom_entries;
+using breakpad_win::g_experiment_chunks_offset;
+using breakpad_win::g_num_of_experiments_offset;
+
+class ChromeAppBreakpadTest : public testing::Test {
+ public:
+ ChromeAppBreakpadTest() {
+ testing::InitCustomInfoEntries();
+ }
+
+ protected:
+ typedef std::vector<base::FieldTrial::NameGroupId> Experiments;
+ void ValidateExperimentChunks(const Experiments& experiments) {
+ UpdateExperiments();
+ EXPECT_STREQ(base::StringPrintf(L"%d", experiments.size()).c_str(),
+ (*g_custom_entries)[g_num_of_experiments_offset].value);
+ // We make a copy of the array that we empty as we find the experiments.
+ Experiments experiments_left(experiments);
+ for (int i = 0; i < kMaxReportedExperimentChunks; ++i) {
+ EXPECT_STREQ(base::StringPrintf(L"experiment-chunk-%i", i + 1).c_str(),
+ (*g_custom_entries)[g_experiment_chunks_offset + i].name);
+ if (experiments_left.empty()) {
+ // All other slots should be empty.
+ EXPECT_STREQ(
+ L"", (*g_custom_entries)[g_experiment_chunks_offset + i].value);
+ } else {
+ // We can't guarantee the order, so we must search for them all.
+ Experiments::const_iterator experiment = experiments_left.begin();
+ while (experiment != experiments_left.end()) {
+ if (wcsstr((*g_custom_entries)[g_experiment_chunks_offset + i].value,
+ base::StringPrintf(
+ L"%x-%x", experiment->name, experiment->group).c_str())) {
+ experiment = experiments_left.erase(experiment);
+ } else {
+ ++experiment;
+ }
+ }
+ }
+ }
+ EXPECT_TRUE(experiments_left.empty());
+ }
+
+ private:
+ static const wchar_t* kNumExperiments;
+ static const size_t kNumExperimentsSize;
+};
+
+const wchar_t* ChromeAppBreakpadTest::kNumExperiments = L"num-experiments";
+const size_t ChromeAppBreakpadTest::kNumExperimentsSize =
+ wcslen(ChromeAppBreakpadTest::kNumExperiments);
+
+TEST_F(ChromeAppBreakpadTest, ExperimentList) {
+ base::FieldTrialList field_trial_list("ABCDE");
+ base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial("All", "To");
+ base::FieldTrial::NameGroupId name_group_id;
+ trial->GetNameGroupId(&name_group_id);
+ Experiments experiments;
+ experiments.push_back(name_group_id);
+ ValidateExperimentChunks(experiments);
+
+ trial = base::FieldTrialList::CreateFieldTrial("There", "You Are");
+ trial->GetNameGroupId(&name_group_id);
+ experiments.push_back(name_group_id);
+ ValidateExperimentChunks(experiments);
+
+ trial = base::FieldTrialList::CreateFieldTrial("Peter", "Sellers");
+ trial->GetNameGroupId(&name_group_id);
+ experiments.push_back(name_group_id);
+ ValidateExperimentChunks(experiments);
+
+ trial = base::FieldTrialList::CreateFieldTrial("Eat me", "Drink me");
+ trial->GetNameGroupId(&name_group_id);
+ experiments.push_back(name_group_id);
+ ValidateExperimentChunks(experiments);
+}
diff --git a/chrome/app/breakpad_win.cc b/chrome/app/breakpad_win.cc
index 10bd402..02794b3 100644
--- a/chrome/app/breakpad_win.cc
+++ b/chrome/app/breakpad_win.cc
@@ -19,11 +19,13 @@
#include "base/memory/scoped_ptr.h"
#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/string16.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/win_util.h"
#include "breakpad/src/client/windows/handler/exception_handler.h"
+#include "chrome/app/breakpad_field_trial_win.h"
#include "chrome/app/hard_error_handler_win.h"
#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_result_codes.h"
@@ -34,6 +36,18 @@
#include "chrome/installer/util/install_util.h"
#include "policy/policy_constants.h"
+namespace breakpad_win {
+
+std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries = NULL;
+size_t g_num_of_experiments_offset = 0;
+size_t g_experiment_chunks_offset = 0;
+
+} // namespace breakpad_win
+
+using breakpad_win::g_custom_entries;
+using breakpad_win::g_experiment_chunks_offset;
+using breakpad_win::g_num_of_experiments_offset;
+
namespace {
// Minidump with stacks, PEB, TEB, and unloaded module list.
@@ -65,19 +79,15 @@ const wchar_t kSystemPrincipalSid[] =L"S-1-5-18";
google_breakpad::ExceptionHandler* g_breakpad = NULL;
google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL;
-// A pointer to the custom entries that we send in the event of a crash. We need
-// this pointer, along with the offsets into it below, so that we can keep the
-// data updated as the state of the browser changes.
-static std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries = NULL;
-static size_t g_url_chunks_offset;
-static size_t g_num_of_extensions_offset;
-static size_t g_extension_ids_offset;
-static size_t g_client_id_offset;
-static size_t g_gpu_info_offset;
-static size_t g_printer_info_offset;
-static size_t g_num_of_views_offset;
-static size_t g_num_switches_offset;
-static size_t g_switches_offset;
+static size_t g_url_chunks_offset = 0;
+static size_t g_num_of_extensions_offset = 0;
+static size_t g_extension_ids_offset = 0;
+static size_t g_client_id_offset = 0;
+static size_t g_gpu_info_offset = 0;
+static size_t g_printer_info_offset = 0;
+static size_t g_num_of_views_offset = 0;
+static size_t g_num_switches_offset = 0;
+static size_t g_switches_offset = 0;
// Maximum length for plugin path to include in plugin crash reports.
const size_t kMaxPluginPathLength = 256;
@@ -253,9 +263,10 @@ google_breakpad::CustomClientInfo* GetCustomInfo(const std::wstring& exe_path,
google_breakpad::CustomInfoEntry(L"num-extensions", L"N/A"));
g_extension_ids_offset = g_custom_entries->size();
- for (int i = 0; i < kMaxReportedActiveExtensions; ++i) {
+ // one-based index for the name suffix.
+ for (int i = 1; i <= kMaxReportedActiveExtensions; ++i) {
g_custom_entries->push_back(google_breakpad::CustomInfoEntry(
- base::StringPrintf(L"extension-%i", i + 1).c_str(), L""));
+ base::StringPrintf(L"extension-%i", i).c_str(), L""));
}
// Add empty values for the gpu_info. We'll put the actual values when we
@@ -276,10 +287,11 @@ google_breakpad::CustomClientInfo* GetCustomInfo(const std::wstring& exe_path,
// Add empty values for the prn_info-*. We'll put the actual values when we
// collect them at this location.
g_printer_info_offset = g_custom_entries->size();
- for (size_t i = 0; i < kMaxReportedPrinterRecords; ++i) {
+ // one-based index for the name suffix.
+ for (size_t i = 1; i <= kMaxReportedPrinterRecords; ++i) {
g_custom_entries->push_back(
google_breakpad::CustomInfoEntry(
- base::StringPrintf(L"prn-info-%d", i + 1).c_str(), L""));
+ base::StringPrintf(L"prn-info-%d", i).c_str(), L""));
}
// Read the id from registry. If reporting has never been enabled
@@ -298,9 +310,10 @@ google_breakpad::CustomClientInfo* GetCustomInfo(const std::wstring& exe_path,
google_breakpad::CustomInfoEntry(L"num-switches", L""));
g_switches_offset = g_custom_entries->size();
- for (int i = 0; i < kMaxSwitches; ++i) {
+ // one-based index for the name suffix.
+ for (int i = 1; i <= kMaxSwitches; ++i) {
g_custom_entries->push_back(google_breakpad::CustomInfoEntry(
- base::StringPrintf(L"switch-%i", i + 1).c_str(), L""));
+ base::StringPrintf(L"switch-%i", i).c_str(), L""));
}
// Fill in the command line arguments using CommandLine::ForCurrentProcess().
@@ -316,9 +329,10 @@ google_breakpad::CustomClientInfo* GetCustomInfo(const std::wstring& exe_path,
// characters, which isn't enough for a URL. As a hack we create 8 entries
// and split the URL across the g_custom_entries.
g_url_chunks_offset = g_custom_entries->size();
- for (int i = 0; i < kMaxUrlChunks; ++i) {
+ // one-based index for the name suffix.
+ for (int i = 1; i <= kMaxUrlChunks; ++i) {
g_custom_entries->push_back(google_breakpad::CustomInfoEntry(
- base::StringPrintf(L"url-chunk-%i", i + 1).c_str(), L""));
+ base::StringPrintf(L"url-chunk-%i", i).c_str(), L""));
}
if (type == L"plugin") {
@@ -332,6 +346,21 @@ google_breakpad::CustomClientInfo* GetCustomInfo(const std::wstring& exe_path,
google_breakpad::CustomInfoEntry(L"num-views", L"N/A"));
}
+ g_num_of_experiments_offset = g_custom_entries->size();
+ g_custom_entries->push_back(
+ google_breakpad::CustomInfoEntry(L"num-experiments", L"N/A"));
+
+ g_experiment_chunks_offset = g_custom_entries->size();
+ // We depend on this in UpdateExperiments...
+ DCHECK_NE(0UL, g_experiment_chunks_offset);
+ // And the test code depends on this.
+ DCHECK_EQ(g_num_of_experiments_offset + 1, g_experiment_chunks_offset);
+ // one-based index for the name suffix.
+ for (int i = 1; i <= kMaxReportedExperimentChunks; ++i) {
+ g_custom_entries->push_back(google_breakpad::CustomInfoEntry(
+ base::StringPrintf(L"experiment-chunk-%i", i).c_str(), L""));
+ }
+
static google_breakpad::CustomClientInfo custom_client_info;
custom_client_info.entries = &g_custom_entries->front();
custom_client_info.count = g_custom_entries->size();
@@ -535,6 +564,15 @@ extern "C" void __declspec(dllexport) __cdecl SetNumberOfViews(
} // namespace
+namespace testing {
+
+// Access to namespace protected functions for testing purposes.
+void InitCustomInfoEntries() {
+ GetCustomInfo(L"", L"", L"");
+}
+
+} // namespace testing
+
bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption,
UINT flags, bool* exit_now) {
// We wrap the call to MessageBoxW with a SEH handler because it some
diff --git a/chrome/app/breakpad_win.h b/chrome/app/breakpad_win.h
index 5299119..3190792 100644
--- a/chrome/app/breakpad_win.h
+++ b/chrome/app/breakpad_win.h
@@ -8,6 +8,26 @@
#include <windows.h>
#include <string>
+#include <vector>
+
+namespace google_breakpad {
+
+struct CustomInfoEntry;
+}
+
+namespace breakpad_win {
+
+// A pointer to the custom entries that we send in the event of a crash. We need
+// this pointer, along with the offsets into it below (and some private ones),
+// so that we can keep the data updated as the state of the browser changes.
+extern std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries;
+
+// These two are here because they are needed by breakpad_field_trial_win as
+// well as breakpad_unittest_win.
+extern size_t g_num_of_experiments_offset;
+extern size_t g_experiment_chunks_offset;
+
+} // namespace breakpad_win
// The maximum number of 64-char URL chunks we will report.
static const int kMaxUrlChunks = 8;
@@ -22,4 +42,11 @@ void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter);
// a dialog asking for permission to continue execution or to exit now.
bool ShowRestartDialogIfCrashed(bool* exit_now);
+namespace testing {
+
+// Testing entry point for calling a function from the unnamed namespace.
+void InitCustomInfoEntries();
+
+}
+
#endif // CHROME_APP_BREAKPAD_WIN_H_
diff --git a/chrome/app/run_all_unittests.cc b/chrome/app/run_all_unittests.cc
new file mode 100644
index 0000000..9beab0d
--- /dev/null
+++ b/chrome/app/run_all_unittests.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_suite.h"
+
+int main(int argc, char **argv) {
+ return base::TestSuite(argc, argv).Run();
+}
diff --git a/chrome/browser/metrics/field_trial_synchronizer.cc b/chrome/browser/metrics/field_trial_synchronizer.cc
index c62336b..5db5b0e 100644
--- a/chrome/browser/metrics/field_trial_synchronizer.cc
+++ b/chrome/browser/metrics/field_trial_synchronizer.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/threading/thread.h"
+#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/render_messages.h"
#include "content/public/browser/browser_thread.h"
@@ -18,6 +19,10 @@ FieldTrialSynchronizer::FieldTrialSynchronizer() {
DCHECK(field_trial_synchronizer_ == NULL);
field_trial_synchronizer_ = this;
base::FieldTrialList::AddObserver(this);
+
+ std::string state;
+ base::FieldTrialList::StatesToString(&state);
+ child_process_logging::InitExperimentList(state);
}
FieldTrialSynchronizer::~FieldTrialSynchronizer() {
@@ -49,6 +54,7 @@ void FieldTrialSynchronizer::OnFieldTrialGroupFinalized(
this,
field_trial_name,
group_name));
+ child_process_logging::AddFieldTrialGroup(field_trial_name, group_name);
}
// static
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi
index 1271a2d..1f71b82 100644
--- a/chrome/chrome_exe.gypi
+++ b/chrome/chrome_exe.gypi
@@ -13,6 +13,8 @@
'enable_wexit_time_destructors': 1,
},
'sources': [
+ 'app/breakpad_field_trial_win.cc',
+ 'app/breakpad_field_trial_win.h',
'app/breakpad_win.cc',
'app/breakpad_win.h',
'app/chrome_exe_main_aura.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 81c6e6b..f06b28e 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2504,6 +2504,83 @@
],
},
{
+ 'target_name': 'chrome_app_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ # unit tests should only depend on
+ # 1) everything that the chrome binaries depend on:
+ '<@(chromium_dependencies)',
+ # 2) test-specific support libraries:
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ 'test_support_common',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'app/breakpad_field_trial_win.cc',
+ 'app/breakpad_win.cc',
+ 'app/breakpad_unittest_win.cc',
+ 'app/hard_error_handler_win.cc',
+ 'app/run_all_unittests.cc'
+ ],
+ 'conditions': [
+ ['OS=="mac"', {
+ # TODO(mark): We really want this for all non-static library targets,
+ # but when we tried to pull it up to the common.gypi level, it broke
+ # other things like the ui, startup, and page_cycler tests. *shrug*
+ 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']},
+
+ # libwebcore.a is so large that ld may not have a sufficiently large
+ # "hole" in its address space into which it can be mmaped by the
+ # time it reaches this library. As of May 10, 2010, libwebcore.a is
+ # about 1GB in some builds. In the Mac OS X 10.5 toolchain, using
+ # Xcode 3.1, ld is only a 32-bit executable, and address space
+ # exhaustion is the result, with ld failing and producing
+ # the message:
+ # ld: in .../libwebcore.a, can't map file, errno=12
+ #
+ # As a workaround, ensure that libwebcore.a appears to ld first when
+ # linking unit_tests. This allows the library to be mmapped when
+ # ld's address space is "wide open." Other libraries are small
+ # enough that they'll be able to "squeeze" into the remaining holes.
+ # The Mac linker isn't so sensitive that moving this library to the
+ # front of the list will cause problems.
+ #
+ # Enough pluses to make get this target prepended to the target's
+ # list of dependencies.
+ 'dependencies+++': [
+ '../third_party/WebKit/Source/WebCore/WebCore.gyp/WebCore.gyp:webcore',
+ ],
+ }],
+ ['OS=="win"', {
+ 'dependencies': [
+ # breakpad is currently only tested on Windows.
+ '../breakpad/breakpad.gyp:*',
+ ],
+ 'conditions': [
+ ['win_use_allocator_shim==1', {
+ 'dependencies': [
+ '<(allocator_target)',
+ ],
+ }],
+ ],
+ 'configurations': {
+ 'Debug_Base': {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ # Forcing incremental build off to try to avoid incremental
+ # linking errors on 64-bit bots too. http://crbug.com/52555
+ 'LinkIncremental': '1',
+ },
+ },
+ },
+ },
+ }],
+ ],
+ },
+ {
# Executable that runs each browser test in a new process.
'target_name': 'browser_tests',
'type': 'executable',
diff --git a/chrome/common/child_process_logging.h b/chrome/common/child_process_logging.h
index ab3750d5..e7c76b3 100644
--- a/chrome/common/child_process_logging.h
+++ b/chrome/common/child_process_logging.h
@@ -24,6 +24,11 @@ struct GPUInfo;
// dependency.
static const int kMaxReportedActiveExtensions = 10;
+// The maximum number of experiment chunks we will report.
+// Also used in chrome/app, but we define it here to avoid a common->app
+// dependency.
+static const int kMaxReportedExperimentChunks = 15;
+
// The maximum number of prn-info-* records.
static const size_t kMaxReportedPrinterRecords = 4;
@@ -98,6 +103,13 @@ void SetPrinterInfo(const char* printer_info);
// values in |command_line|.
void SetCommandLine(const CommandLine* command_line);
+// Initialize the list of experiment info to send along with crash reports.
+void InitExperimentList(const std::string& state);
+
+// Add a new experiment group info to send along with crash reports.
+void AddFieldTrialGroup(const std::string& field_trial_name,
+ const std::string& group_name);
+
#if defined(OS_LINUX) || defined(OS_OPENBSD) || defined(OS_MACOSX)
// Sets the product channel data to send along with crash reports to |channel|.
void SetChannel(const std::string& channel);
diff --git a/chrome/common/child_process_logging_mac.mm b/chrome/common/child_process_logging_mac.mm
index 0c13534..bb00f1c 100644
--- a/chrome/common/child_process_logging_mac.mm
+++ b/chrome/common/child_process_logging_mac.mm
@@ -220,6 +220,15 @@ void SetCommandLine(const CommandLine* command_line) {
}
}
+void InitExperimentList(const std::string& state) {
+ // TODO(mad): Implement this.
+}
+
+void AddFieldTrialGroup(const std::string& field_trial_name,
+ const std::string& group_name) {
+ // TODO(mad): Implement this.
+}
+
void SetChannel(const std::string& channel) {
// This should match the corresponding string in breakpad_win.cc.
NSString* const kChannelKey = @"channel";
diff --git a/chrome/common/child_process_logging_posix.cc b/chrome/common/child_process_logging_posix.cc
index 7dc012e..e409259 100644
--- a/chrome/common/child_process_logging_posix.cc
+++ b/chrome/common/child_process_logging_posix.cc
@@ -143,6 +143,15 @@ void SetCommandLine(const CommandLine* command_line) {
g_switches[kMaxSwitchesSize - 1] = '\0';
}
+void InitExperimentList(const std::string& state) {
+ // TODO(mad): Implement this.
+}
+
+void AddFieldTrialGroup(const std::string& field_trial_name,
+ const std::string& group_name) {
+ // TODO(mad): Implement this.
+}
+
void SetChannel(const std::string& channel) {
strncpy(g_channel, channel.c_str(), kChannelSize - 1);
g_channel[kChannelSize - 1] = '\0';
diff --git a/chrome/common/child_process_logging_win.cc b/chrome/common/child_process_logging_win.cc
index 5a1732e..8004451a 100644
--- a/chrome/common/child_process_logging_win.cc
+++ b/chrome/common/child_process_logging_win.cc
@@ -48,6 +48,15 @@ typedef void (__cdecl *MainSetNumberOfViews)(int);
// void __declspec(dllexport) __cdecl SetCommandLine
typedef void (__cdecl *MainSetCommandLine)(const CommandLine*);
+// exported in breakpad_field_trial_win.cc:
+// void __declspec(dllexport) __cdecl InitExperimentList
+typedef void (__cdecl *MainInitExperimentList)(const std::string&);
+
+// exported in breakpad_field_trial_win.cc:
+// void __declspec(dllexport) __cdecl AddFieldTrialGroup
+typedef void (__cdecl *MainAddFieldTrialGroup)(const std::string&,
+ const std::string&);
+
void SetActiveURL(const GURL& url) {
static MainSetActiveURL set_active_url = NULL;
// note: benign race condition on set_active_url.
@@ -182,6 +191,35 @@ void SetCommandLine(const CommandLine* command_line) {
(set_command_line)(command_line);
}
+void InitExperimentList(const std::string& state) {
+ static MainInitExperimentList init_experiment_list = NULL;
+ if (!init_experiment_list) {
+ HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName);
+ if (!exe_module)
+ return;
+ init_experiment_list = reinterpret_cast<MainInitExperimentList>(
+ GetProcAddress(exe_module, "InitExperimentList"));
+ if (!init_experiment_list)
+ return;
+ }
+ (init_experiment_list)(state);
+}
+
+void AddFieldTrialGroup(const std::string& field_trial_name,
+ const std::string& group_name) {
+ static MainAddFieldTrialGroup add_field_trial_group = NULL;
+ if (!add_field_trial_group) {
+ HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName);
+ if (!exe_module)
+ return;
+ add_field_trial_group = reinterpret_cast<MainAddFieldTrialGroup>(
+ GetProcAddress(exe_module, "AddFieldTrialGroup"));
+ if (!add_field_trial_group)
+ return;
+ }
+ (add_field_trial_group)(field_trial_name, group_name);
+}
+
void SetNumberOfViews(int number_of_views) {
static MainSetNumberOfViews set_number_of_views = NULL;
if (!set_number_of_views) {
diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc
index 2ec16dd..4808919 100644
--- a/chrome/renderer/chrome_render_process_observer.cc
+++ b/chrome/renderer/chrome_render_process_observer.cc
@@ -15,6 +15,7 @@
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/threading/platform_thread.h"
+#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_localization_peer.h"
@@ -222,6 +223,11 @@ ChromeRenderProcessObserver::ChromeRenderProcessObserver(
std::string error;
base::LoadNativeLibrary(FilePath(L"crypt32.dll"), &error);
#endif
+
+ // Setup initial set of crash dump data for Field Trials.
+ std::string state;
+ base::FieldTrialList::StatesToString(&state);
+ child_process_logging::InitExperimentList(state);
}
ChromeRenderProcessObserver::~ChromeRenderProcessObserver() {