diff options
author | mad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-26 14:40:22 +0000 |
---|---|---|
committer | mad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-26 14:40:22 +0000 |
commit | c215cc0447d7a86964dd82bec54e91e01c0c6d0b (patch) | |
tree | 11b8923075c2790d4ca0bf4bd027edfb6fc09caa | |
parent | 9a3b349b671809ce7d790a6e0218689cabb7d9b2 (diff) | |
download | chromium_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.cc | 102 | ||||
-rw-r--r-- | chrome/app/breakpad_field_trial_win.h | 11 | ||||
-rw-r--r-- | chrome/app/breakpad_unittest_win.cc | 89 | ||||
-rw-r--r-- | chrome/app/breakpad_win.cc | 80 | ||||
-rw-r--r-- | chrome/app/breakpad_win.h | 27 | ||||
-rw-r--r-- | chrome/app/run_all_unittests.cc | 9 | ||||
-rw-r--r-- | chrome/browser/metrics/field_trial_synchronizer.cc | 8 | ||||
-rw-r--r-- | chrome/chrome_exe.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 77 | ||||
-rw-r--r-- | chrome/common/child_process_logging.h | 12 | ||||
-rw-r--r-- | chrome/common/child_process_logging_mac.mm | 9 | ||||
-rw-r--r-- | chrome/common/child_process_logging_posix.cc | 9 | ||||
-rw-r--r-- | chrome/common/child_process_logging_win.cc | 38 | ||||
-rw-r--r-- | chrome/renderer/chrome_render_process_observer.cc | 6 |
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() { |