diff options
26 files changed, 1060 insertions, 702 deletions
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index 2d0c709..aafdd6d 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc @@ -15,7 +15,6 @@ #include "build/build_config.h" #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/defaults.h" -#include "chrome/browser/diagnostics/diagnostics_main.h" #include "chrome/browser/policy/policy_path_parser.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_content_client.h" @@ -78,6 +77,10 @@ #if defined(OS_ANDROID) #include "chrome/common/descriptors_android.h" +#else +// Diagnostics is only available on non-android platforms. +#include "chrome/browser/diagnostics/diagnostics_controller.h" +#include "chrome/browser/diagnostics/diagnostics_writer.h" #endif #if defined(USE_X11) @@ -365,16 +368,6 @@ bool ChromeMainDelegate::BasicStartupComplete(int* exit_code) { #endif #endif // OS_POSIX - // No support for ANDROID yet as DiagnosticsMain needs wchar support. -#if !defined(OS_ANDROID) - // If we are in diagnostics mode this is the end of the line. After the - // diagnostics are run the process will invariably exit. - if (command_line.HasSwitch(switches::kDiagnostics)) { - *exit_code = DiagnosticsMain(command_line); - return true; - } -#endif - #if defined(OS_WIN) // Must do this before any other usage of command line! if (HasDeprecatedArguments(command_line.GetCommandLineString())) { @@ -383,6 +376,46 @@ bool ChromeMainDelegate::BasicStartupComplete(int* exit_code) { } #endif + chrome::RegisterPathProvider(); +#if defined(OS_CHROMEOS) + chromeos::RegisterPathProvider(); +#endif +#if !defined(DISABLE_NACL) && defined(OS_LINUX) + nacl::RegisterPathProvider(); +#endif + +// No support for ANDROID yet as DiagnosticsController needs wchar support. +// TODO(gspencer): That's not true anymore, or at least there are no w-string +// references anymore. Not sure if that means this can be enabled on Android or +// not though: it still uses string16. As there is no easily accessible command +// line on Android, I'm not sure this is a big deal, at least for purposes of +// troubleshooting with a customer. +#if !defined(OS_ANDROID) + // If we are in diagnostics mode this is the end of the line: after the + // diagnostics are run the process will invariably exit. + if (command_line.HasSwitch(switches::kDiagnostics)) { + diagnostics::DiagnosticsWriter::FormatType format = + diagnostics::DiagnosticsWriter::HUMAN; + if (command_line.HasSwitch(switches::kDiagnosticsFormat)) { + std::string format_str = + command_line.GetSwitchValueASCII(switches::kDiagnosticsFormat); + if (format_str == "machine") { + format = diagnostics::DiagnosticsWriter::MACHINE; + } else if (format_str == "log") { + format = diagnostics::DiagnosticsWriter::LOG; + } else { + DCHECK_EQ("human", format_str); + } + } + + diagnostics::DiagnosticsWriter writer(format); + *exit_code = diagnostics::DiagnosticsController::GetInstance()->Run( + command_line, &writer); + diagnostics::DiagnosticsController::GetInstance()->ClearResults(); + return true; + } +#endif + content::SetContentClient(&chrome_content_client_); return false; @@ -481,14 +514,6 @@ void ChromeMainDelegate::PreSandboxStartup() { std::string process_type = command_line.GetSwitchValueASCII(switches::kProcessType); - chrome::RegisterPathProvider(); -#if defined(OS_CHROMEOS) - chromeos::RegisterPathProvider(); -#endif -#if !defined(DISABLE_NACL) && defined(OS_LINUX) - nacl::RegisterPathProvider(); -#endif - #if defined(OS_MACOSX) || defined(USE_LINUX_BREAKPAD) breakpad::SetBreakpadClient(g_chrome_breakpad_client.Pointer()); #endif diff --git a/chrome/browser/diagnostics/diagnostics_controller.cc b/chrome/browser/diagnostics/diagnostics_controller.cc new file mode 100644 index 0000000..a578beb --- /dev/null +++ b/chrome/browser/diagnostics/diagnostics_controller.cc @@ -0,0 +1,49 @@ +// Copyright 2013 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/browser/diagnostics/diagnostics_controller.h" + +#include <string> + +#include "base/command_line.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "chrome/browser/diagnostics/diagnostics_model.h" +#include "chrome/browser/diagnostics/diagnostics_writer.h" +#include "chrome/common/chrome_switches.h" + +namespace diagnostics { + +DiagnosticsController* DiagnosticsController::GetInstance() { + return Singleton<DiagnosticsController>::get(); +} + +DiagnosticsController::DiagnosticsController() : writer_(NULL) {} + +DiagnosticsController::~DiagnosticsController() {} + +const DiagnosticsModel& DiagnosticsController::GetResults() const { + return *model_; +} + +bool DiagnosticsController::HasResults() { + return (model_.get() && model_->GetTestRunCount() > 0); +} + +void DiagnosticsController::ClearResults() { model_.reset(); } + +// This entry point is called from ChromeMain() when very few things +// have been initialized, so be careful what you use. +int DiagnosticsController::Run(const CommandLine& command_line, + DiagnosticsWriter* writer) { + writer_ = writer; + + model_.reset(MakeDiagnosticsModel(command_line)); + model_->RunAll(writer_); + + return 0; +} + +} // namespace diagnostics diff --git a/chrome/browser/diagnostics/diagnostics_controller.h b/chrome/browser/diagnostics/diagnostics_controller.h new file mode 100644 index 0000000..706a10f --- /dev/null +++ b/chrome/browser/diagnostics/diagnostics_controller.h @@ -0,0 +1,51 @@ +// Copyright 2013 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_BROWSER_DIAGNOSTICS_DIAGNOSTICS_CONTROLLER_H_ +#define CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_CONTROLLER_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/memory/singleton.h" + +class CommandLine; + +namespace diagnostics { + +class DiagnosticsWriter; +class DiagnosticsModel; + +class DiagnosticsController { + public: + static DiagnosticsController* GetInstance(); + + // Entry point for the diagnostics mode. Returns zero if able to run + // diagnostics successfully, regardless of the results of the diagnostics. + int Run(const CommandLine& command_line, DiagnosticsWriter* writer); + + // Returns a model with the results that have accumulated. They can then be + // queried for their attributes for human consumption later. + const DiagnosticsModel& GetResults() const; + + // Returns true if there are any results available. + bool HasResults(); + + // Clears any results that have accumulated. After calling this, do not call + // GetResults until after Run is called again. + void ClearResults(); + + private: + friend struct DefaultSingletonTraits<DiagnosticsController>; + + DiagnosticsController(); + ~DiagnosticsController(); + + scoped_ptr<DiagnosticsModel> model_; + DiagnosticsWriter* writer_; + + DISALLOW_COPY_AND_ASSIGN(DiagnosticsController); +}; + +} // namespace diagnostics + +#endif // CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_CONTROLLER_H_ diff --git a/chrome/browser/diagnostics/diagnostics_main.cc b/chrome/browser/diagnostics/diagnostics_main.cc deleted file mode 100644 index 7d02a23..0000000 --- a/chrome/browser/diagnostics/diagnostics_main.cc +++ /dev/null @@ -1,367 +0,0 @@ -// 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/browser/diagnostics/diagnostics_main.h" - -#include "build/build_config.h" - -#if defined(OS_POSIX) -#include <stdio.h> -#include <unistd.h> -#endif - -#include <string> - -#include "base/basictypes.h" -#include "base/command_line.h" -#include "base/i18n/icu_util.h" -#include "base/logging.h" -#include "base/strings/stringprintf.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "chrome/browser/diagnostics/diagnostics_model.h" -#include "chrome/common/chrome_paths.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/base/ui_base_paths.h" - -namespace { -// This is a minimalistic interface to wrap the platform console. This will be -// eventually replaced by a view that can be subclassed for each platform and -// that the approved look and feel. -class SimpleConsole { - public: - enum Color { - DEFAULT, - RED, - GREEN, - }; - - virtual ~SimpleConsole() { } - - // Init must be called before using any other method. If it returns - // false there would be no console output. - virtual bool Init() = 0; - - // Writes a string to the console with the current color. - virtual bool Write(const std::wstring& text) = 0; - - // Called when the program is about to exit. - virtual void OnQuit() = 0; - - // Sets the foreground and background color. - virtual bool SetColor(Color color) = 0; - - // Create an appropriate SimpleConsole instance. May return NULL if there is - // no implementation for the current platform. - static SimpleConsole* Create(); -}; - -#if defined(OS_WIN) -// Wrapper for the windows console operating in high-level IO mode. -class WinConsole : public SimpleConsole { - public: - // The ctor allocates a console always. This avoids having to ask - // the user to start chrome from a command prompt. - WinConsole() - : std_out_(INVALID_HANDLE_VALUE), - std_in_(INVALID_HANDLE_VALUE) { - } - - virtual ~WinConsole() { - ::FreeConsole(); - } - - virtual bool Init() { - ::AllocConsole(); - return SetIOHandles(); - } - - virtual bool Write(const std::wstring& txt) { - DWORD sz = txt.size(); - return (TRUE == ::WriteConsoleW(std_out_, txt.c_str(), sz, &sz, NULL)); - } - - // Reads a string from the console. Internally it is limited to 256 - // characters. - virtual void OnQuit() { - // Block here so the user can see the results. - SetColor(SimpleConsole::DEFAULT); - Write(L"Press [enter] to continue\n"); - wchar_t buf[256]; - DWORD read = arraysize(buf); - ::ReadConsoleW(std_in_, buf, read, &read, NULL); - } - - // Sets the foreground and background color. - virtual bool SetColor(Color color) { - uint16 color_combo = - FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY; - switch (color) { - case RED: - color_combo = FOREGROUND_RED|FOREGROUND_INTENSITY; - break; - case GREEN: - color_combo = FOREGROUND_GREEN|FOREGROUND_INTENSITY; - break; - case DEFAULT: - break; - default: - NOTREACHED(); - } - return (TRUE == ::SetConsoleTextAttribute(std_out_, color_combo)); - } - - private: - bool SetIOHandles() { - std_out_ = ::GetStdHandle(STD_OUTPUT_HANDLE); - std_in_ = ::GetStdHandle(STD_INPUT_HANDLE); - return ((std_out_ != INVALID_HANDLE_VALUE) && - (std_in_ != INVALID_HANDLE_VALUE)); - } - - // The input and output handles to the screen. They seem to be - // implemented as pipes but they have non-documented protocol. - HANDLE std_out_; - HANDLE std_in_; - - DISALLOW_COPY_AND_ASSIGN(WinConsole); -}; - -SimpleConsole* SimpleConsole::Create() { - return new WinConsole(); -} - -#elif defined(OS_POSIX) - -class PosixConsole : public SimpleConsole { - public: - PosixConsole() : use_color_(false) { } - - virtual bool Init() OVERRIDE { - // Technically, we should also check the terminal capabilities before using - // color, but in practice this is unlikely to be an issue. - use_color_ = isatty(STDOUT_FILENO); - return true; - } - - virtual bool Write(const std::wstring& text) OVERRIDE { - printf("%s", base::SysWideToNativeMB(text).c_str()); - return true; - } - - virtual void OnQuit() OVERRIDE { - // The "press enter to continue" prompt isn't very unixy, so only do that on - // Windows. - } - - virtual bool SetColor(Color color) OVERRIDE { - if (!use_color_) - return false; - - const char* code = "\033[m"; - switch (color) { - case RED: - code = "\033[1;31m"; - break; - case GREEN: - code = "\033[1;32m"; - break; - case DEFAULT: - break; - default: - NOTREACHED(); - } - printf("%s", code); - return true; - } - - private: - bool use_color_; - - DISALLOW_COPY_AND_ASSIGN(PosixConsole); -}; - -SimpleConsole* SimpleConsole::Create() { - return new PosixConsole(); -} - -#else // !defined(OS_WIN) && !defined(OS_POSIX) - -SimpleConsole* SimpleConsole::Create() { - return NULL; -} -#endif - -// This class wraps a SimpleConsole for the specific use case of -// writing the results of the diagnostic tests. -// TODO(cpu) figure out the localization strategy. -class TestWriter { - public: - // The |console| must be valid and properly initialized. This - // class does not own it. - explicit TestWriter(SimpleConsole* console) - : console_(console), - failures_(0) { - } - - // How many tests reported failure. - int failures() { return failures_; } - - // Write an informational line of text in white over black. - bool WriteInfoText(const std::wstring& txt) { - console_->SetColor(SimpleConsole::DEFAULT); - return console_->Write(txt); - } - - bool WriteInfoText(const std::string& txt) { - return WriteInfoText(UTF8ToWide(txt)); - } - - // Write a result block. It consist of two lines. The first line - // has [PASS] or [FAIL] with |name| and the second line has - // the text in |extra|. - bool WriteResult(bool success, const std::wstring& name, - const std::wstring& extra) { - if (success) { - console_->SetColor(SimpleConsole::GREEN); - console_->Write(L"[PASS] "); - } else { - console_->SetColor(SimpleConsole::RED); - console_->Write(L"[FAIL] "); - failures_++; - } - WriteInfoText(name + L"\n"); - std::wstring second_line(L" "); - second_line.append(extra); - return WriteInfoText(second_line + L"\n\n"); - } - - private: - SimpleConsole* console_; - - // Keeps track of how many tests reported failure. - int failures_; - - DISALLOW_COPY_AND_ASSIGN(TestWriter); -}; - -std::string PrintableUSCurrentTime() { - base::Time::Exploded exploded = {0}; - base::Time::Now().UTCExplode(&exploded); - return base::StringPrintf("%d:%d:%d.%d:%d:%d", - exploded.year, - exploded.month, - exploded.day_of_month, - exploded.hour, - exploded.minute, - exploded.second); -} - -// This class is a basic test controller. In this design the view (TestWriter) -// and the model (DiagnosticsModel) do not talk to each other directly but they -// are mediated by the controller. This has a name: 'passive view'. -// More info at http://martinfowler.com/eaaDev/PassiveScreen.html -class TestController : public DiagnosticsModel::Observer { - public: - explicit TestController(TestWriter* writer) - : model_(NULL), - writer_(writer) { - } - - // Run all the diagnostics of |model| and invoke the view as the model - // callbacks arrive. - void Run(DiagnosticsModel* model) { - writer_->WriteInfoText(L"Chrome Diagnostics Mode ("); - writer_->WriteInfoText(PrintableUSCurrentTime() + ")\n"); - if (!model) { - writer_->WriteResult(false, L"Diagnostics start", L"model is null"); - return; - } - bool icu_result = icu_util::Initialize(); - if (!icu_result) { - writer_->WriteResult(false, L"Diagnostics start", L"ICU failure"); - return; - } - ResourceBundle::InitSharedInstanceWithLocale(std::string(), NULL); - int count = model->GetTestAvailableCount(); - writer_->WriteInfoText(base::StringPrintf( - "%d available test(s)\n\n", count)); - model->RunAll(this); - } - - // Next four are overridden from DiagnosticsModel::Observer. - virtual void OnProgress(int id, - int percent, - DiagnosticsModel* model) OVERRIDE { - } - - virtual void OnSkipped(int id, DiagnosticsModel* model) OVERRIDE { - // TODO(cpu): display skipped tests. - } - - virtual void OnFinished(int id, DiagnosticsModel* model) OVERRIDE { - // As each test completes we output the results. - ShowResult(&model->GetTest(id)); - } - - virtual void OnDoneAll(DiagnosticsModel* model) OVERRIDE { - if (writer_->failures() > 0) { - writer_->WriteInfoText(base::StringPrintf( - "DONE. %d failure(s)\n\n", writer_->failures())); - } else { - writer_->WriteInfoText(L"DONE\n\n"); - } - } - - private: - void ShowResult(DiagnosticsModel::TestInfo* test_info) { - bool success = (DiagnosticsModel::TEST_OK == test_info->GetResult()); - writer_->WriteResult(success, UTF16ToWide(test_info->GetTitle()), - UTF16ToWide(test_info->GetAdditionalInfo())); - } - - DiagnosticsModel* model_; - TestWriter* writer_; - - DISALLOW_COPY_AND_ASSIGN(TestController); -}; -} // namespace - -// This entry point is called from ChromeMain() when very few things -// have been initialized. To wit: -// -(win) Breakpad -// -(macOS) base::EnableTerminationOnHeapCorruption() -// -(macOS) base::EnableTerminationOnOutOfMemory() -// -(all) RegisterInvalidParamHandler() -// -(all) base::AtExitManager::AtExitManager() -// -(macOS) base::ScopedNSAutoreleasePool -// -(posix) base::GlobalDescriptors::GetInstance()->Set(kPrimaryIPCChannel) -// -(linux) base::GlobalDescriptors::GetInstance()->Set(kCrashDumpSignal) -// -(posix) setlocale(LC_ALL,..) -// -(all) CommandLine::Init(); - -int DiagnosticsMain(const CommandLine& command_line) { - // If we can't initialize the console exit right away. - SimpleConsole* console = SimpleConsole::Create(); - if (!console || !console->Init()) - return 1; - - // We need to have the path providers registered. They both - // return void so there is no early error signal that we can use. - ui::RegisterPathProvider(); - chrome::RegisterPathProvider(); - - TestWriter writer(console); - DiagnosticsModel* model = MakeDiagnosticsModel(command_line); - TestController controller(&writer); - - // Run all the diagnostic tests. - controller.Run(model); - delete model; - - console->OnQuit(); - delete console; - return 0; -} diff --git a/chrome/browser/diagnostics/diagnostics_main.h b/chrome/browser/diagnostics/diagnostics_main.h deleted file mode 100644 index 0ce1404..0000000 --- a/chrome/browser/diagnostics/diagnostics_main.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2009 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_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MAIN_H_ -#define CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MAIN_H_ - -class CommandLine; - -// Entry point for the diagnostics mode. Most of the initialization that you -// can see in ChromeMain() will be repeated here or will be done differently. -int DiagnosticsMain(const CommandLine& command_line); - - -#endif // CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MAIN_H_ diff --git a/chrome/browser/diagnostics/diagnostics_model.cc b/chrome/browser/diagnostics/diagnostics_model.cc index 6f96d06..b52e0a5 100644 --- a/chrome/browser/diagnostics/diagnostics_model.cc +++ b/chrome/browser/diagnostics/diagnostics_model.cc @@ -19,30 +19,31 @@ #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" +namespace diagnostics { + namespace { // Embodies the commonalities of the model across platforms. It manages the // list of tests and can loop over them. The main job of the platform specific // code becomes: -// 1- Inserting the appropiate tests into |tests_| -// 2- Overriding RunTest() to wrap it with the appropiate fatal exception +// 1- Inserting the appropriate tests into |tests_| +// 2- Overriding RunTest() to wrap it with the appropriate fatal exception // handler for the OS. // This class owns the all the tests and will only delete them upon // destruction. class DiagnosticsModelImpl : public DiagnosticsModel { public: - DiagnosticsModelImpl() : tests_run_(0) { - } + DiagnosticsModelImpl() : tests_run_(0) {} virtual ~DiagnosticsModelImpl() { STLDeleteElements(&tests_); } - virtual int GetTestRunCount() OVERRIDE { + virtual int GetTestRunCount() const OVERRIDE { return tests_run_; } - virtual int GetTestAvailableCount() OVERRIDE { + virtual int GetTestAvailableCount() const OVERRIDE { return tests_.size(); } @@ -54,20 +55,23 @@ class DiagnosticsModelImpl : public DiagnosticsModel { if (!do_next) break; } - observer->OnDoneAll(this); + if (observer) + observer->OnDoneAll(this); } - virtual TestInfo& GetTest(size_t id) OVERRIDE { - return *tests_[id]; + virtual const TestInfo& GetTest(size_t index) OVERRIDE { + return *tests_[index]; } protected: // Run a particular test. Return false if no other tests should be run. - virtual bool RunTest(DiagnosticTest* test, Observer* observer, size_t index) { + virtual bool RunTest(DiagnosticsTest* test, + Observer* observer, + size_t index) { return test->Execute(observer, this, index); } - typedef std::vector<DiagnosticTest*> TestArray; + typedef std::vector<DiagnosticsTest*> TestArray; TestArray tests_; int tests_run_; @@ -153,6 +157,10 @@ class DiagnosticsModelPosix : public DiagnosticsModelImpl { tests_.push_back(MakeSqliteThumbnailsDbTest()); tests_.push_back(MakeSqliteAppCacheDbTest()); tests_.push_back(MakeSqliteWebDatabaseTrackerDbTest()); +#if defined(OS_CHROMEOS) + tests_.push_back(MakeSqliteNssCertDbTest()); + tests_.push_back(MakeSqliteNssKeyDbTest()); +#endif } private: @@ -176,3 +184,5 @@ DiagnosticsModel* MakeDiagnosticsModel(const CommandLine& cmdline) { return new DiagnosticsModelPosix(); #endif } + +} // namespace diagnostics diff --git a/chrome/browser/diagnostics/diagnostics_model.h b/chrome/browser/diagnostics/diagnostics_model.h index 466020b..1af3ae3 100644 --- a/chrome/browser/diagnostics/diagnostics_model.h +++ b/chrome/browser/diagnostics/diagnostics_model.h @@ -5,14 +5,16 @@ #ifndef CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MODEL_H_ #define CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MODEL_H_ -#include "base/strings/string16.h" +#include <string> +#include "base/time/time.h" class CommandLine; +namespace diagnostics { + // The chrome diagnostics system is a model-view-controller system. The Model // responsible for holding and running the individual tests and providing a // uniform interface for querying the outcome. -// TODO(cpu): The view and the controller are not yet built. class DiagnosticsModel { public: // A particular test can be in one of the following states. @@ -31,13 +33,8 @@ class DiagnosticsModel { class Observer { public: virtual ~Observer() {} - // Called once upon test start with |percent| = 0 and periodically as the - // test progresses. There is no cancellation method. - virtual void OnProgress(int id, int percent, DiagnosticsModel* model) = 0; - // Called if the test in question cannot be run. - virtual void OnSkipped(int id, DiagnosticsModel* model) = 0; - // Called when the test has finished regardless of outcome. - virtual void OnFinished(int id, DiagnosticsModel* model) = 0; + // Called when a test has finished regardless of outcome. + virtual void OnFinished(int index, DiagnosticsModel* model) = 0; // Called once all the test are run. virtual void OnDoneAll(DiagnosticsModel* model) = 0; }; @@ -46,32 +43,45 @@ class DiagnosticsModel { class TestInfo { public: virtual ~TestInfo() {} - // A human readable, localized string that tells you what is being tested. - virtual string16 GetTitle() = 0; + // A parse-able ASCII string that indicates what is being tested. + virtual std::string GetId() const = 0; + // A human readable string that tells you what is being tested. + // This is not localized: it is only meant for developer consumption. + virtual std::string GetTitle() const = 0; // The result of running the test. If called before the test is ran the // answer is TEST_NOT_RUN. - virtual TestResult GetResult() = 0; - // A human readable, localized string that tells you what happened. If + virtual TestResult GetResult() const = 0; + // A human readable string that tells you more about what happened. If // called before the test is run it returns the empty string. - virtual string16 GetAdditionalInfo() = 0; + // This is not localized: it is only meant for developer consumption. + virtual std::string GetAdditionalInfo() const = 0; + // A test-specific code representing what happened. If called before the + // test is run, it should return -1. + virtual int GetOutcomeCode() const = 0; + // Returns the system time when the test was performed. + virtual base::Time GetStartTime() const = 0; + // Returns the system time when the test was finished. + virtual base::Time GetEndTime() const = 0; }; virtual ~DiagnosticsModel() {} // Returns how many tests have been run. - virtual int GetTestRunCount() = 0; + virtual int GetTestRunCount() const = 0; // Returns how many tests are available. This value never changes. - virtual int GetTestAvailableCount() =0; + virtual int GetTestAvailableCount() const = 0; // Runs all the available tests, the |observer| callbacks will be called as - // the test progress and thus cannot be null. + // the diagnostics progress. |observer| maybe NULL if no observation is + // needed. virtual void RunAll(DiagnosticsModel::Observer* observer) = 0; - // Get the information for a particular test. Do not keep a pointer to the - // returned object. - virtual TestInfo& GetTest(size_t id) = 0; + // Get the information for a particular test. Lifetime of returned object is + // limited to the lifetime of this model. + virtual const TestInfo& GetTest(size_t index) = 0; }; // The factory for the model. The main purpose is to hide the creation of // different models for different platforms. DiagnosticsModel* MakeDiagnosticsModel(const CommandLine& cmdline); +} // namespace diagnostics #endif // CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MODEL_H_ diff --git a/chrome/browser/diagnostics/diagnostics_model_unittest.cc b/chrome/browser/diagnostics/diagnostics_model_unittest.cc index e362cd4..d70a299 100644 --- a/chrome/browser/diagnostics/diagnostics_model_unittest.cc +++ b/chrome/browser/diagnostics/diagnostics_model_unittest.cc @@ -8,7 +8,9 @@ #include "base/compiler_specific.h" #include "testing/gtest/include/gtest/gtest.h" -// Basic harness to adquire and release the Diagnostic model object. +namespace diagnostics { + +// Basic harness to acquire and release the Diagnostic model object. class DiagnosticsModelTest : public testing::Test { protected: DiagnosticsModelTest() @@ -36,27 +38,15 @@ class UTObserver: public DiagnosticsModel::Observer { public: UTObserver() : done_(false), - progress_called_(0), finished_(0), id_of_failed_stop_test(-1) { } - virtual void OnProgress(int id, - int percent, - DiagnosticsModel* model) OVERRIDE { - EXPECT_TRUE(model != NULL); - ++progress_called_; - } - - virtual void OnSkipped(int id, DiagnosticsModel* model) OVERRIDE { - EXPECT_TRUE(model != NULL); - } - - virtual void OnFinished(int id, DiagnosticsModel* model) OVERRIDE { + virtual void OnFinished(int index, DiagnosticsModel* model) OVERRIDE { EXPECT_TRUE(model != NULL); ++finished_; - if (model->GetTest(id).GetResult() == DiagnosticsModel::TEST_FAIL_STOP) { - id_of_failed_stop_test = id; + if (model->GetTest(index).GetResult() == DiagnosticsModel::TEST_FAIL_STOP) { + id_of_failed_stop_test = index; ASSERT_TRUE(false); } } @@ -68,25 +58,26 @@ class UTObserver: public DiagnosticsModel::Observer { bool done() const { return done_; } - int progress_called() const { return progress_called_; } - int finished() const { return finished_;} private: bool done_; - int progress_called_; int finished_; int id_of_failed_stop_test; }; -// We currently have more tests operational on windows. +// This is the count of tests on each platform. #if defined(OS_WIN) const int kDiagnosticsTestCount = 19; #elif defined(OS_MACOSX) const int kDiagnosticsTestCount = 16; #elif defined(OS_POSIX) +#if defined(OS_CHROMEOS) +const int kDiagnosticsTestCount = 19; +#else const int kDiagnosticsTestCount = 17; #endif +#endif // Test that the initial state is correct. TEST_F(DiagnosticsModelTest, BeforeRun) { @@ -103,7 +94,8 @@ TEST_F(DiagnosticsModelTest, RunAll) { EXPECT_FALSE(observer.done()); model_->RunAll(&observer); EXPECT_TRUE(observer.done()); - EXPECT_GT(observer.progress_called(), 0); EXPECT_EQ(kDiagnosticsTestCount, model_->GetTestRunCount()); EXPECT_EQ(kDiagnosticsTestCount, observer.finished()); } + +} // namespace diagnostics diff --git a/chrome/browser/diagnostics/diagnostics_test.cc b/chrome/browser/diagnostics/diagnostics_test.cc index 64d4797..fe08dd6 100644 --- a/chrome/browser/diagnostics/diagnostics_test.cc +++ b/chrome/browser/diagnostics/diagnostics_test.cc @@ -9,45 +9,61 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" -DiagnosticTest::DiagnosticTest(const string16& title) - : title_(title), result_(DiagnosticsModel::TEST_NOT_RUN) { -} +namespace diagnostics { -DiagnosticTest::~DiagnosticTest() { -} +DiagnosticsTest::DiagnosticsTest(const std::string& id, + const std::string& title) + : id_(id), + title_(title), + outcome_code_(-1), + result_(DiagnosticsModel::TEST_NOT_RUN) {} + +DiagnosticsTest::~DiagnosticsTest() {} -bool DiagnosticTest::Execute(DiagnosticsModel::Observer* observer, - DiagnosticsModel* model, - size_t index) { +bool DiagnosticsTest::Execute(DiagnosticsModel::Observer* observer, + DiagnosticsModel* model, + size_t index) { + start_time_ = base::Time::Now(); result_ = DiagnosticsModel::TEST_RUNNING; - observer->OnProgress(index, 0, model); bool keep_going = ExecuteImpl(observer); - observer->OnFinished(index, model); + if (observer) + observer->OnFinished(index, model); return keep_going; } -string16 DiagnosticTest::GetTitle() { - return title_; -} - -DiagnosticsModel::TestResult DiagnosticTest::GetResult() { - return result_; -} - -string16 DiagnosticTest::GetAdditionalInfo() { - return additional_info_; -} - -void DiagnosticTest::RecordOutcome(const string16& additional_info, - DiagnosticsModel::TestResult result) { +void DiagnosticsTest::RecordOutcome(int outcome_code, + const std::string& additional_info, + DiagnosticsModel::TestResult result) { + end_time_ = base::Time::Now(); + outcome_code_ = outcome_code; additional_info_ = additional_info; result_ = result; } // static -base::FilePath DiagnosticTest::GetUserDefaultProfileDir() { +base::FilePath DiagnosticsTest::GetUserDefaultProfileDir() { base::FilePath path; if (!PathService::Get(chrome::DIR_USER_DATA, &path)) return base::FilePath(); return path.AppendASCII(chrome::kInitialProfile); } + +std::string DiagnosticsTest::GetId() const { return id_; } + +std::string DiagnosticsTest::GetTitle() const { return title_; } + +DiagnosticsModel::TestResult DiagnosticsTest::GetResult() const { + return result_; +} + +int DiagnosticsTest::GetOutcomeCode() const { return outcome_code_; } + +std::string DiagnosticsTest::GetAdditionalInfo() const { + return additional_info_; +} + +base::Time DiagnosticsTest::GetStartTime() const { return start_time_; } + +base::Time DiagnosticsTest::GetEndTime() const { return end_time_; } + +} // namespace diagnostics diff --git a/chrome/browser/diagnostics/diagnostics_test.h b/chrome/browser/diagnostics/diagnostics_test.h index eed176d..20e44d9 100644 --- a/chrome/browser/diagnostics/diagnostics_test.h +++ b/chrome/browser/diagnostics/diagnostics_test.h @@ -6,16 +6,17 @@ #define CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_TEST_H_ #include "base/compiler_specific.h" -#include "base/strings/string16.h" #include "chrome/browser/diagnostics/diagnostics_model.h" namespace base { class FilePath; } +namespace diagnostics { + // Represents a single diagnostic test and encapsulates the common // functionality across platforms as well. -// It also Implements the TestInfo interface providing the storage +// It also implements the TestInfo interface providing the storage // for the outcome of the test. // Specific tests need (minimally) only to: // 1- override ExecuteImpl() to implement the test. @@ -23,52 +24,61 @@ class FilePath; // at the end of the test. // 3- Optionally call observer->OnProgress() if the test is long. // 4- Optionally call observer->OnSkipped() if the test cannot be run. -class DiagnosticTest : public DiagnosticsModel::TestInfo { +class DiagnosticsTest : public DiagnosticsModel::TestInfo { public: - // |title| is the human readable, localized string that says that - // the objective of the test is. - explicit DiagnosticTest(const string16& title); + // |id| is a parse-able ASCII ID string that uniquely identifies the test. It + // should only have letters, numbers and underscores in it (and no spaces). + // |title| is the human readable string that says what the objective of the + // test is. + DiagnosticsTest(const std::string& id, const std::string& title); - virtual ~DiagnosticTest(); + virtual ~DiagnosticsTest(); // Runs the test. Returning false signals that no more tests should be run. // The actual outcome of the test should be set using the RecordXX functions. bool Execute(DiagnosticsModel::Observer* observer, DiagnosticsModel* model, size_t index); - virtual string16 GetTitle() OVERRIDE; - - virtual DiagnosticsModel::TestResult GetResult() OVERRIDE; - - virtual string16 GetAdditionalInfo() OVERRIDE; - - void RecordStopFailure(const string16& additional_info) { - RecordOutcome(additional_info, DiagnosticsModel::TEST_FAIL_STOP); + void RecordStopFailure(int outcome_code, const std::string& additional_info) { + RecordOutcome( + outcome_code, additional_info, DiagnosticsModel::TEST_FAIL_STOP); } - void RecordFailure(const string16& additional_info) { - RecordOutcome(additional_info, DiagnosticsModel::TEST_FAIL_CONTINUE); + void RecordFailure(int outcome_code, const std::string& additional_info) { + RecordOutcome( + outcome_code, additional_info, DiagnosticsModel::TEST_FAIL_CONTINUE); } - void RecordSuccess(const string16& additional_info) { - RecordOutcome(additional_info, DiagnosticsModel::TEST_OK); + void RecordSuccess(const std::string& additional_info) { + RecordOutcome(0, additional_info, DiagnosticsModel::TEST_OK); } - void RecordOutcome(const string16& additional_info, + void RecordOutcome(int outcome_code, + const std::string& additional_info, DiagnosticsModel::TestResult result); static base::FilePath GetUserDefaultProfileDir(); + // DiagnosticsModel::TestInfo overrides + virtual std::string GetId() const OVERRIDE; + virtual std::string GetTitle() const OVERRIDE; + virtual DiagnosticsModel::TestResult GetResult() const OVERRIDE; + virtual std::string GetAdditionalInfo() const OVERRIDE; + virtual int GetOutcomeCode() const OVERRIDE; + virtual base::Time GetStartTime() const OVERRIDE; + virtual base::Time GetEndTime() const OVERRIDE; protected: - // The id needs to be overridden by derived classes and must uniquely - // identify this test so other test can refer to it. - virtual int GetId() = 0; // Derived classes override this method do perform the actual test. virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) = 0; - string16 title_; - string16 additional_info_; + const std::string id_; + const std::string title_; + std::string additional_info_; + int outcome_code_; DiagnosticsModel::TestResult result_; + base::Time start_time_; + base::Time end_time_; }; +} // namespace diagnostics #endif // CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_TEST_H_ diff --git a/chrome/browser/diagnostics/diagnostics_writer.cc b/chrome/browser/diagnostics/diagnostics_writer.cc new file mode 100644 index 0000000..bf49e3e7 --- /dev/null +++ b/chrome/browser/diagnostics/diagnostics_writer.cc @@ -0,0 +1,281 @@ +// Copyright 2013 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/browser/diagnostics/diagnostics_writer.h" + +#include "build/build_config.h" + +#if defined(OS_POSIX) +#include <stdio.h> +#include <unistd.h> +#endif + +#include <string> + +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/logging.h" +#include "base/strings/string16.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/common/chrome_switches.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/ui_base_paths.h" + +namespace diagnostics { + +// This is a minimalistic interface to wrap the platform console. +class SimpleConsole { + public: + enum Color { + DEFAULT, + RED, + GREEN, + }; + + virtual ~SimpleConsole() {} + + // Init must be called before using any other method. If it returns + // false there will be no console output. + virtual bool Init() = 0; + + // Writes a string to the console with the current color. + virtual bool Write(const string16& text) = 0; + + // Called when the program is about to exit. + virtual void OnQuit() = 0; + + // Sets the foreground text color. + virtual bool SetColor(Color color) = 0; + + // Create an appropriate SimpleConsole instance. May return NULL if there is + // no implementation for the current platform. + static SimpleConsole* Create(); +}; + +#if defined(OS_WIN) +namespace { + +// Wrapper for the windows console operating in high-level IO mode. +class WinConsole : public SimpleConsole { + public: + // The ctor allocates a console. This avoids having to ask the user to start + // chrome from a command prompt. + WinConsole() + : std_out_(INVALID_HANDLE_VALUE), + std_in_(INVALID_HANDLE_VALUE) { + ::AllocConsole(); + } + + virtual ~WinConsole() { + ::FreeConsole(); + } + + virtual bool Init() { + return SetIOHandles(); + } + + virtual bool Write(const string16& txt) { + DWORD sz = txt.size(); + return (TRUE == ::WriteConsoleW(std_out_, txt.c_str(), sz, &sz, NULL)); + } + + // Reads a string from the console. Internally it is limited to 256 + // characters. + virtual void OnQuit() { + // Block here so the user can see the results. + SetColor(SimpleConsole::DEFAULT); + Write(L"Press [enter] to continue\n"); + wchar_t buf[256]; + DWORD read = arraysize(buf); + ::ReadConsoleW(std_in_, buf, read, &read, NULL); + } + + // Sets the foreground and background color. + virtual bool SetColor(Color color) { + uint16 color_combo = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | + FOREGROUND_INTENSITY; + switch (color) { + case RED: + color_combo = FOREGROUND_RED | FOREGROUND_INTENSITY; + break; + case GREEN: + color_combo = FOREGROUND_GREEN | FOREGROUND_INTENSITY; + break; + case DEFAULT: + break; + default: + NOTREACHED(); + } + return (TRUE == ::SetConsoleTextAttribute(std_out_, color_combo)); + } + + private: + bool SetIOHandles() { + std_out_ = ::GetStdHandle(STD_OUTPUT_HANDLE); + std_in_ = ::GetStdHandle(STD_INPUT_HANDLE); + return ((std_out_ != INVALID_HANDLE_VALUE) && + (std_in_ != INVALID_HANDLE_VALUE)); + } + + // The input and output handles to the screen. They seem to be + // implemented as pipes but they have non-documented protocol. + HANDLE std_out_; + HANDLE std_in_; + + DISALLOW_COPY_AND_ASSIGN(WinConsole); +}; + +} // namespace + +SimpleConsole* SimpleConsole::Create() { return new WinConsole(); } + +#elif defined(OS_POSIX) +namespace { + +class PosixConsole : public SimpleConsole { + public: + PosixConsole() : use_color_(false) {} + + virtual bool Init() OVERRIDE { + // Technically, we should also check the terminal capabilities before using + // color, but in practice this is unlikely to be an issue. + use_color_ = isatty(STDOUT_FILENO); + return true; + } + + virtual bool Write(const string16& text) OVERRIDE { + // We're assuming that the terminal is using UTF-8 encoding. + printf("%s", UTF16ToUTF8(text).c_str()); + return true; + } + + virtual void OnQuit() OVERRIDE { + // The "press enter to continue" prompt isn't very unixy, so only do that on + // Windows. + } + + virtual bool SetColor(Color color) OVERRIDE { + if (!use_color_) + return false; + + const char* code = "\033[m"; + switch (color) { + case RED: + code = "\033[1;31m"; + break; + case GREEN: + code = "\033[1;32m"; + break; + case DEFAULT: + break; + default: + NOTREACHED(); + } + printf("%s", code); + return true; + } + + private: + bool use_color_; + + DISALLOW_COPY_AND_ASSIGN(PosixConsole); +}; + +} // namespace + +SimpleConsole* SimpleConsole::Create() { return new PosixConsole(); } + +#else // !defined(OS_WIN) && !defined(OS_POSIX) +SimpleConsole* SimpleConsole::Create() { return NULL; } +#endif + +/////////////////////////////////////////////////////////// +// DiagnosticsWriter + +DiagnosticsWriter::DiagnosticsWriter(FormatType format) + : failures_(0), format_(format) { + // Only create consoles for non-log output. + if (format_ != LOG) { + console_.reset(SimpleConsole::Create()); + console_->Init(); + } +} + +DiagnosticsWriter::~DiagnosticsWriter() { + if (console_.get()) + console_->OnQuit(); +} + +bool DiagnosticsWriter::WriteInfoLine(const std::string& info_text) { + if (format_ == LOG) { + LOG(WARNING) << info_text; + return true; + } else { + if (console_.get()) { + console_->SetColor(SimpleConsole::DEFAULT); + console_->Write(UTF8ToUTF16(info_text + "\n")); + } + } + return true; +} + +void DiagnosticsWriter::OnFinished(int index, DiagnosticsModel* model) { + const DiagnosticsModel::TestInfo& test_info = model->GetTest(index); + bool success = (DiagnosticsModel::TEST_OK == test_info.GetResult()); + WriteResult(success, + test_info.GetId(), + test_info.GetTitle(), + test_info.GetOutcomeCode(), + test_info.GetAdditionalInfo()); +} + +void DiagnosticsWriter::OnDoneAll(DiagnosticsModel* model) { + WriteInfoLine( + base::StringPrintf("Finished %d tests.", model->GetTestRunCount())); +} + +bool DiagnosticsWriter::WriteResult(bool success, + const std::string& id, + const std::string& name, + int outcome_code, + const std::string& extra) { + std::string result; + SimpleConsole::Color color; + + if (success) { + result = "[PASS] "; + color = SimpleConsole::GREEN; + } else { + color = SimpleConsole::RED; + result = "[FAIL] "; + failures_++; + } + + if (format_ != LOG) { + if (console_.get()) { + console_->SetColor(color); + console_->Write(ASCIIToUTF16(result)); + } + if (format_ == MACHINE) { + return WriteInfoLine(base::StringPrintf( + "%03d %s (%s)", outcome_code, id.c_str(), extra.c_str())); + } else { + return WriteInfoLine(name + "\n " + extra + "\n"); + } + } else { + if (!success) { + // For log output, we only care about the tests that failed. + return WriteInfoLine(base::StringPrintf("%s%03d %s (%s)", + result.c_str(), + outcome_code, + id.c_str(), + extra.c_str())); + } + } + return true; +} + +} // namespace diagnostics diff --git a/chrome/browser/diagnostics/diagnostics_writer.h b/chrome/browser/diagnostics/diagnostics_writer.h new file mode 100644 index 0000000..1fad047 --- /dev/null +++ b/chrome/browser/diagnostics/diagnostics_writer.h @@ -0,0 +1,66 @@ +// Copyright 2013 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_BROWSER_DIAGNOSTICS_DIAGNOSTICS_WRITER_H_ +#define CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_WRITER_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/diagnostics/diagnostics_model.h" + +namespace diagnostics { + +// Console base class used internally. +class SimpleConsole; + +class DiagnosticsWriter : public DiagnosticsModel::Observer { + public: + // The type of formatting done by this writer. + enum FormatType { + MACHINE, + LOG, + HUMAN + }; + + explicit DiagnosticsWriter(FormatType format); + virtual ~DiagnosticsWriter(); + + // How many tests reported failure. + int failures() { return failures_; } + + // What format are we writing things in. + FormatType format() const { return format_; } + + // Write an informational line of text in white over black. String must be + // UTF8 encoded. A newline will be added for non-LOG output formats. + bool WriteInfoLine(const std::string& info_text); + + // DiagnosticsModel::Observer overrides + virtual void OnFinished(int id, DiagnosticsModel* model) OVERRIDE; + virtual void OnDoneAll(DiagnosticsModel* model) OVERRIDE; + + private: + // Write a result block. For humans, it consists of two lines. The first line + // has [PASS] or [FAIL] with |name| and the second line has the text in + // |extra|. For machine and log formats, we just have [PASS] or [FAIL], + // followed by the exact error code and the id. Name and extra strings must be + // UTF8 encoded, as they are user-facing strings. + bool WriteResult(bool success, + const std::string& id, + const std::string& name, + int outcome_code, + const std::string& extra); + + scoped_ptr<SimpleConsole> console_; + + // Keeps track of how many tests reported failure. + int failures_; + FormatType format_; + + DISALLOW_COPY_AND_ASSIGN(DiagnosticsWriter); +}; + +} // namespace diagnostics + +#endif // CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_WRITER_H_ diff --git a/chrome/browser/diagnostics/recon_diagnostics.cc b/chrome/browser/diagnostics/recon_diagnostics.cc index b66fd03..fc69ad7 100644 --- a/chrome/browser/diagnostics/recon_diagnostics.cc +++ b/chrome/browser/diagnostics/recon_diagnostics.cc @@ -19,7 +19,6 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_version_info.h" -#include "ui/base/text/bytes_formatting.h" #if defined(OS_WIN) #include "base/win/windows_version.h" @@ -31,21 +30,35 @@ // diagnostic tests. Here we check for the existence of critical files. // TODO(cpu): Define if it makes sense to localize strings. -// TODO(cpu): There are a few maximum file sizes hardcoded in this file +// TODO(cpu): There are a few maximum file sizes hard-coded in this file // that have little or no theoretical or experimental ground. Find a way // to justify them. +namespace diagnostics { + +const char kConflictingDllsTest[] = "ConflictingDlls"; +const char kDiskSpaceTest[] = "DiskSpace"; +const char kInstallTypeTest[] = "InstallType"; +const char kJSONBookmarksTest[] = "JSONBookmarks"; +const char kJSONLocalStateTest[] = "JSONLocalState"; +const char kJSONProfileTest[] = "JSONProfile"; +const char kOperatingSystemTest[] = "OperatingSystem"; +const char kPathDictionariesTest[] = "PathDictionaries"; +const char kPathLocalStateTest[] = "PathLocalState"; +const char kPathResourcesTest[] = "PathResources"; +const char kPathUserDataTest[] = "PathUserData"; +const char kVersionTest[] = "Version"; + namespace { class InstallTypeTest; InstallTypeTest* g_install_type = 0; // Check that the flavor of the operating system is supported. -class OperatingSystemTest : public DiagnosticTest { +class OperatingSystemTest : public DiagnosticsTest { public: - OperatingSystemTest() : DiagnosticTest(ASCIIToUTF16("Operating System")) {} - - virtual int GetId() OVERRIDE { return 0; } + OperatingSystemTest() + : DiagnosticsTest(kOperatingSystemTest, "Operating System") {} virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) OVERRIDE { #if defined(OS_WIN) @@ -53,16 +66,17 @@ class OperatingSystemTest : public DiagnosticTest { if ((version < base::win::VERSION_XP) || ((version == base::win::VERSION_XP) && (base::win::OSInfo::GetInstance()->service_pack().major < 2))) { - RecordFailure(ASCIIToUTF16("Must have Windows XP SP2 or later")); + RecordFailure(DIAG_RECON_PRE_WINDOW_XP_SP2, + "Must have Windows XP SP2 or later"); return false; } #else - // TODO(port): define the OS criteria for Linux and Mac. +// TODO(port): define the OS criteria for Linux and Mac. #endif // defined(OS_WIN) - RecordSuccess(ASCIIToUTF16(base::StringPrintf( - "%s %s", - base::SysInfo::OperatingSystemName().c_str(), - base::SysInfo::OperatingSystemVersion().c_str()))); + RecordSuccess( + base::StringPrintf("%s %s", + base::SysInfo::OperatingSystemName().c_str(), + base::SysInfo::OperatingSystemVersion().c_str())); return true; } @@ -71,11 +85,10 @@ class OperatingSystemTest : public DiagnosticTest { }; // Check if any conflicting DLLs are loaded. -class ConflictingDllsTest : public DiagnosticTest { +class ConflictingDllsTest : public DiagnosticsTest { public: - ConflictingDllsTest() : DiagnosticTest(ASCIIToUTF16("Conflicting modules")) {} - - virtual int GetId() OVERRIDE { return 0; } + ConflictingDllsTest() + : DiagnosticsTest(kConflictingDllsTest, "Conflicting modules") {} virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) OVERRIDE { #if defined(OS_WIN) @@ -85,38 +98,40 @@ class ConflictingDllsTest : public DiagnosticTest { scoped_ptr<ListValue> list(model->GetModuleList()); if (!model->confirmed_bad_modules_detected() && !model->suspected_bad_modules_detected()) { - RecordSuccess(ASCIIToUTF16("No conflicting modules found")); + RecordSuccess("No conflicting modules found"); return true; } - string16 failures = ASCIIToUTF16("Possibly conflicting modules:"); + std::string failures = "Possibly conflicting modules:"; DictionaryValue* dictionary; for (size_t i = 0; i < list->GetSize(); ++i) { if (!list->GetDictionary(i, &dictionary)) - RecordFailure(ASCIIToUTF16("Dictionary lookup failed")); + RecordFailure(DIAG_RECON_DICTIONARY_LOOKUP_FAILED, + "Dictionary lookup failed"); int status; - string16 location; - string16 name; + std::string location; + std::string name; if (!dictionary->GetInteger("status", &status)) - RecordFailure(ASCIIToUTF16("No 'status' field found")); + RecordFailure(DIAG_RECON_NO_STATUS_FIELD, "No 'status' field found"); if (status < ModuleEnumerator::SUSPECTED_BAD) continue; if (!dictionary->GetString("location", &location)) { - RecordFailure(ASCIIToUTF16("No 'location' field found")); + RecordFailure(DIAG_RECON_NO_LOCATION_FIELD, + "No 'location' field found"); return true; } if (!dictionary->GetString("name", &name)) { - RecordFailure(ASCIIToUTF16("No 'name' field found")); + RecordFailure(DIAG_RECON_NO_NAME_FIELD, "No 'name' field found"); return true; } - failures += ASCIIToUTF16("\n") + location + name; + failures += "\n" + location + name; } - RecordFailure(failures); + RecordFailure(DIAG_RECON_CONFLICTING_MODULES, failures); return true; #else - RecordFailure(ASCIIToUTF16("Not implemented")); + RecordFailure(DIAG_RECON_NOT_IMPLEMENTED, "Not implemented"); return true; #endif // defined(OS_WIN) } @@ -126,25 +141,23 @@ class ConflictingDllsTest : public DiagnosticTest { }; // Check if it is system install or per-user install. -class InstallTypeTest : public DiagnosticTest { +class InstallTypeTest : public DiagnosticsTest { public: - InstallTypeTest() : DiagnosticTest(ASCIIToUTF16("Install Type")), - user_level_(false) {} - - virtual int GetId() OVERRIDE { return 0; } + InstallTypeTest() + : DiagnosticsTest(kInstallTypeTest, "Install Type"), user_level_(false) {} virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) OVERRIDE { #if defined(OS_WIN) base::FilePath chrome_exe; if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { - RecordFailure(ASCIIToUTF16("Path provider failure")); + RecordFailure(DIAG_RECON_INSTALL_PATH_PROVIDER, "Path provider failure"); return false; } user_level_ = InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()); const char* type = user_level_ ? "User Level" : "System Level"; - string16 install_type(ASCIIToUTF16(type)); + std::string install_type(type); #else - string16 install_type(ASCIIToUTF16("System Level")); + std::string install_type("System Level"); #endif // defined(OS_WIN) RecordSuccess(install_type); g_install_type = this; @@ -159,21 +172,19 @@ class InstallTypeTest : public DiagnosticTest { }; // Check the version of Chrome. -class VersionTest : public DiagnosticTest { +class VersionTest : public DiagnosticsTest { public: - VersionTest() : DiagnosticTest(ASCIIToUTF16("Browser Version")) {} - - virtual int GetId() OVERRIDE { return 0; } + VersionTest() : DiagnosticsTest(kVersionTest, "Browser Version") {} virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) OVERRIDE { chrome::VersionInfo version_info; if (!version_info.is_valid()) { - RecordFailure(ASCIIToUTF16("No Version")); + RecordFailure(DIAG_RECON_NO_VERSION, "No Version"); return true; } std::string current_version = version_info.Version(); if (current_version.empty()) { - RecordFailure(ASCIIToUTF16("Empty Version")); + RecordFailure(DIAG_RECON_EMPTY_VERSION, "Empty Version"); return true; } std::string version_modifier = @@ -183,7 +194,7 @@ class VersionTest : public DiagnosticTest { #if defined(GOOGLE_CHROME_BUILD) current_version += " GCB"; #endif // defined(GOOGLE_CHROME_BUILD) - RecordSuccess(ASCIIToUTF16(current_version)); + RecordSuccess(current_version); return true; } @@ -193,51 +204,51 @@ class VersionTest : public DiagnosticTest { struct TestPathInfo { const char* test_name; - int path_id; + const char* test_id; + int path_id; bool is_directory; bool is_optional; bool test_writable; int64 max_size; }; -const int64 kOneKilo = 1024; -const int64 kOneMeg = 1024 * kOneKilo; +const int64 kOneKilobyte = 1024; +const int64 kOneMegabyte = 1024 * kOneKilobyte; const TestPathInfo kPathsToTest[] = { - {"User data Directory", chrome::DIR_USER_DATA, - true, false, true, 850 * kOneMeg}, - {"Local state file", chrome::FILE_LOCAL_STATE, - false, false, true, 500 * kOneKilo}, - {"Dictionaries Directory", chrome::DIR_APP_DICTIONARIES, - true, true, false, 0}, - {"Resources file", chrome::FILE_RESOURCES_PACK, - false, false, false, 0} + {"User data Directory", kPathUserDataTest, chrome::DIR_USER_DATA, true, false, + true, 850 * kOneMegabyte}, + {"Local state file", kPathLocalStateTest, chrome::FILE_LOCAL_STATE, false, + false, true, 500 * kOneKilobyte}, + {"Dictionaries Directory", kPathDictionariesTest, + chrome::DIR_APP_DICTIONARIES, true, true, false, 0}, + {"Resources file", kPathResourcesTest, chrome::FILE_RESOURCES_PACK, false, + false, false, 0} }; // Check that the user's data directory exists and the paths are writable. -// If it is a systemwide install some paths are not expected to be writable. +// If it is a system-wide install some paths are not expected to be writable. // This test depends on |InstallTypeTest| having run successfully. -class PathTest : public DiagnosticTest { +class PathTest : public DiagnosticsTest { public: explicit PathTest(const TestPathInfo& path_info) - : DiagnosticTest(ASCIIToUTF16(path_info.test_name)), + : DiagnosticsTest(path_info.test_id, path_info.test_name), path_info_(path_info) {} - virtual int GetId() OVERRIDE { return 0; } - virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) OVERRIDE { if (!g_install_type) { - RecordStopFailure(ASCIIToUTF16("dependency failure")); + RecordStopFailure(DIAG_RECON_DEPENDENCY, "Install dependency failure"); return false; } base::FilePath dir_or_file; if (!PathService::Get(path_info_.path_id, &dir_or_file)) { - RecordStopFailure(ASCIIToUTF16("Path provider failure")); + RecordStopFailure(DIAG_RECON_PATH_PROVIDER, "Path provider failure"); return false; } if (!file_util::PathExists(dir_or_file)) { - RecordFailure(ASCIIToUTF16("Path not found: ") + - dir_or_file.LossyDisplayName()); + RecordFailure( + DIAG_RECON_PATH_NOT_FOUND, + "Path not found: " + UTF16ToUTF8(dir_or_file.LossyDisplayName())); return true; } @@ -248,32 +259,32 @@ class PathTest : public DiagnosticTest { file_util::GetFileSize(dir_or_file, &dir_or_file_size); } if (!dir_or_file_size && !path_info_.is_optional) { - RecordFailure(ASCIIToUTF16("Cannot obtain size for: ") + - dir_or_file.LossyDisplayName()); + RecordFailure(DIAG_RECON_CANNOT_OBTAIN_SIZE, + "Cannot obtain size for: " + + UTF16ToUTF8(dir_or_file.LossyDisplayName())); return true; } - string16 printable_size = ui::FormatBytes(dir_or_file_size); + std::string printable_size = base::Int64ToString(dir_or_file_size); if (path_info_.max_size > 0) { if (dir_or_file_size > path_info_.max_size) { - RecordFailure(ASCIIToUTF16("Path contents too large (") + - printable_size + - ASCIIToUTF16(") for: ") + - dir_or_file.LossyDisplayName()); + RecordFailure(DIAG_RECON_FILE_TOO_LARGE, + "Path contents too large (" + printable_size + ") for: " + + UTF16ToUTF8(dir_or_file.LossyDisplayName())); return true; } } if (g_install_type->system_level() && !path_info_.test_writable) { - RecordSuccess(ASCIIToUTF16("Path exists")); + RecordSuccess("Path exists"); return true; } if (!file_util::PathIsWritable(dir_or_file)) { - RecordFailure(ASCIIToUTF16("Path is not writable: ") + - dir_or_file.LossyDisplayName()); + RecordFailure(DIAG_RECON_NOT_WRITABLE, + "Path is not writable: " + + UTF16ToUTF8(dir_or_file.LossyDisplayName())); return true; } - RecordSuccess(ASCIIToUTF16("Path exists and is writable: ") - + printable_size); + RecordSuccess("Path exists and is writable: " + printable_size); return true; } @@ -282,13 +293,11 @@ class PathTest : public DiagnosticTest { DISALLOW_COPY_AND_ASSIGN(PathTest); }; -// Check that the disk space in the volume where the user data dir normally -// lives is not dangerously low. -class DiskSpaceTest : public DiagnosticTest { +// Check that the disk space in the volume where the user data directory +// normally lives is not dangerously low. +class DiskSpaceTest : public DiagnosticsTest { public: - DiskSpaceTest() : DiagnosticTest(ASCIIToUTF16("Disk Space")) {} - - virtual int GetId() OVERRIDE { return 0; } + DiskSpaceTest() : DiagnosticsTest(kDiskSpaceTest, "Disk Space") {} virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) OVERRIDE { base::FilePath data_dir; @@ -296,15 +305,16 @@ class DiskSpaceTest : public DiagnosticTest { return false; int64 disk_space = base::SysInfo::AmountOfFreeDiskSpace(data_dir); if (disk_space < 0) { - RecordFailure(ASCIIToUTF16("Unable to query free space")); + RecordFailure(DIAG_RECON_UNABLE_TO_QUERY, "Unable to query free space"); return true; } - string16 printable_size = ui::FormatBytes(disk_space); - if (disk_space < 80 * kOneMeg) { - RecordFailure(ASCIIToUTF16("Low disk space : ") + printable_size); + std::string printable_size = base::Int64ToString(disk_space); + if (disk_space < 80 * kOneMegabyte) { + RecordFailure(DIAG_RECON_LOW_DISK_SPACE, + "Low disk space: " + printable_size); return true; } - RecordSuccess(ASCIIToUTF16("Free space : ") + printable_size); + RecordSuccess("Free space: " + printable_size); return true; } @@ -313,36 +323,35 @@ class DiskSpaceTest : public DiagnosticTest { }; // Checks that a given json file can be correctly parsed. -class JSONTest : public DiagnosticTest { +class JSONTest : public DiagnosticsTest { public: JSONTest(const base::FilePath& path, - const string16& name, + const std::string& id, + const std::string& name, int64 max_file_size) - : DiagnosticTest(name), path_(path), max_file_size_(max_file_size) { - } - - virtual int GetId() OVERRIDE { return 0; } + : DiagnosticsTest(id, name), path_(path), max_file_size_(max_file_size) {} virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) OVERRIDE { if (!file_util::PathExists(path_)) { - RecordFailure(ASCIIToUTF16("File not found")); + RecordFailure(DIAG_RECON_FILE_NOT_FOUND, "File not found"); return true; } int64 file_size; if (!file_util::GetFileSize(path_, &file_size)) { - RecordFailure(ASCIIToUTF16("Cannot obtain file size")); + RecordFailure(DIAG_RECON_CANNOT_OBTAIN_FILE_SIZE, + "Cannot obtain file size"); return true; } if (file_size > max_file_size_) { - RecordFailure(ASCIIToUTF16("File too big")); + RecordFailure(DIAG_RECON_FILE_TOO_BIG, "File too big"); return true; } // Being small enough, we can process it in-memory. std::string json_data; if (!file_util::ReadFileToString(path_, &json_data)) { - RecordFailure(ASCIIToUTF16( - "Could not open file. Possibly locked by other process")); + RecordFailure(DIAG_RECON_UNABLE_TO_OPEN_FILE, + "Could not open file. Possibly locked by another process"); return true; } @@ -354,11 +363,11 @@ class JSONTest : public DiagnosticTest { if (error_message.empty()) { error_message = "Parse error " + base::IntToString(error_code); } - RecordFailure(UTF8ToUTF16(error_message)); + RecordFailure(DIAG_RECON_PARSE_ERROR, error_message); return true; } - RecordSuccess(ASCIIToUTF16("File parsed OK")); + RecordSuccess("File parsed OK"); return true; } @@ -370,57 +379,50 @@ class JSONTest : public DiagnosticTest { } // namespace -DiagnosticTest* MakeUserDirTest() { - return new PathTest(kPathsToTest[0]); -} +DiagnosticsTest* MakeUserDirTest() { return new PathTest(kPathsToTest[0]); } -DiagnosticTest* MakeLocalStateFileTest() { +DiagnosticsTest* MakeLocalStateFileTest() { return new PathTest(kPathsToTest[1]); } -DiagnosticTest* MakeDictonaryDirTest() { +DiagnosticsTest* MakeDictonaryDirTest() { return new PathTest(kPathsToTest[2]); } -DiagnosticTest* MakeResourcesFileTest() { +DiagnosticsTest* MakeResourcesFileTest() { return new PathTest(kPathsToTest[3]); } -DiagnosticTest* MakeVersionTest() { - return new VersionTest(); -} +DiagnosticsTest* MakeVersionTest() { return new VersionTest(); } -DiagnosticTest* MakeDiskSpaceTest() { - return new DiskSpaceTest(); -} +DiagnosticsTest* MakeDiskSpaceTest() { return new DiskSpaceTest(); } -DiagnosticTest* MakeOperatingSystemTest() { - return new OperatingSystemTest(); -} +DiagnosticsTest* MakeOperatingSystemTest() { return new OperatingSystemTest(); } -DiagnosticTest* MakeConflictingDllsTest() { - return new ConflictingDllsTest(); -} +DiagnosticsTest* MakeConflictingDllsTest() { return new ConflictingDllsTest(); } -DiagnosticTest* MakeInstallTypeTest() { - return new InstallTypeTest(); -} +DiagnosticsTest* MakeInstallTypeTest() { return new InstallTypeTest(); } -DiagnosticTest* MakePreferencesTest() { - base::FilePath path = DiagnosticTest::GetUserDefaultProfileDir(); +DiagnosticsTest* MakePreferencesTest() { + base::FilePath path = DiagnosticsTest::GetUserDefaultProfileDir(); path = path.Append(chrome::kPreferencesFilename); - return new JSONTest(path, ASCIIToUTF16("Profile JSON"), 100 * kOneKilo); + return new JSONTest( + path, kJSONProfileTest, "Profile JSON", 100 * kOneKilobyte); } -DiagnosticTest* MakeBookMarksTest() { - base::FilePath path = DiagnosticTest::GetUserDefaultProfileDir(); +DiagnosticsTest* MakeBookMarksTest() { + base::FilePath path = DiagnosticsTest::GetUserDefaultProfileDir(); path = path.Append(chrome::kBookmarksFileName); - return new JSONTest(path, ASCIIToUTF16("BookMarks JSON"), 2 * kOneMeg); + return new JSONTest( + path, kJSONBookmarksTest, "Bookmarks JSON", 2 * kOneMegabyte); } -DiagnosticTest* MakeLocalStateTest() { +DiagnosticsTest* MakeLocalStateTest() { base::FilePath path; PathService::Get(chrome::DIR_USER_DATA, &path); path = path.Append(chrome::kLocalStateFilename); - return new JSONTest(path, ASCIIToUTF16("Local State JSON"), 50 * kOneKilo); + return new JSONTest( + path, kJSONLocalStateTest, "Local State JSON", 50 * kOneKilobyte); } + +} // namespace diagnostics diff --git a/chrome/browser/diagnostics/recon_diagnostics.h b/chrome/browser/diagnostics/recon_diagnostics.h index 3e04601..ac23e55 100644 --- a/chrome/browser/diagnostics/recon_diagnostics.h +++ b/chrome/browser/diagnostics/recon_diagnostics.h @@ -7,17 +7,76 @@ #include "chrome/browser/diagnostics/diagnostics_test.h" -DiagnosticTest* MakeOperatingSystemTest(); -DiagnosticTest* MakeConflictingDllsTest(); -DiagnosticTest* MakeInstallTypeTest(); -DiagnosticTest* MakeVersionTest(); -DiagnosticTest* MakeUserDirTest(); -DiagnosticTest* MakeLocalStateFileTest(); -DiagnosticTest* MakeDictonaryDirTest(); -DiagnosticTest* MakeResourcesFileTest(); -DiagnosticTest* MakeDiskSpaceTest(); -DiagnosticTest* MakePreferencesTest(); -DiagnosticTest* MakeBookMarksTest(); -DiagnosticTest* MakeLocalStateTest(); +namespace diagnostics { + +enum OutcomeCodes { + DIAG_RECON_SUCCESS, + + // OperatingSystemTest + DIAG_RECON_PRE_WINDOW_XP_SP2, + + // ConflictingDllsTest + DIAG_RECON_DICTIONARY_LOOKUP_FAILED, + DIAG_RECON_NO_STATUS_FIELD, + DIAG_RECON_NO_NAME_FIELD, + DIAG_RECON_NO_LOCATION_FIELD, + DIAG_RECON_CONFLICTING_MODULES, + DIAG_RECON_NOT_IMPLEMENTED, + + // InstallTypeTest + DIAG_RECON_INSTALL_PATH_PROVIDER, + + // VersionTest + DIAG_RECON_NO_VERSION, + DIAG_RECON_EMPTY_VERSION, + + // PathTest + DIAG_RECON_DEPENDENCY, + DIAG_RECON_PATH_PROVIDER, + DIAG_RECON_PATH_NOT_FOUND, + DIAG_RECON_CANNOT_OBTAIN_SIZE, + DIAG_RECON_FILE_TOO_LARGE, + DIAG_RECON_NOT_WRITABLE, + + // DiskSpaceTest + DIAG_RECON_UNABLE_TO_QUERY, + DIAG_RECON_LOW_DISK_SPACE, + + // JSONTest + DIAG_RECON_FILE_NOT_FOUND, + DIAG_RECON_CANNOT_OBTAIN_FILE_SIZE, + DIAG_RECON_FILE_TOO_BIG, + DIAG_RECON_UNABLE_TO_OPEN_FILE, + DIAG_RECON_PARSE_ERROR, +}; + +// Identifiers for the tests. +extern const char kConflictingDllsTest[]; +extern const char kDiskSpaceTest[]; +extern const char kInstallTypeTest[]; +extern const char kJSONBookmarksTest[]; +extern const char kJSONLocalStateTest[]; +extern const char kJSONProfileTest[]; +extern const char kOperatingSystemTest[]; +extern const char kPathDictionariesTest[]; +extern const char kPathLocalStateTest[]; +extern const char kPathResourcesTest[]; +extern const char kPathUserDataTest[]; +extern const char kVersionTest[]; + +DiagnosticsTest* MakeOperatingSystemTest(); +DiagnosticsTest* MakeConflictingDllsTest(); +DiagnosticsTest* MakeInstallTypeTest(); +DiagnosticsTest* MakeVersionTest(); +DiagnosticsTest* MakeUserDirTest(); +DiagnosticsTest* MakeLocalStateFileTest(); +DiagnosticsTest* MakeDictonaryDirTest(); +DiagnosticsTest* MakeResourcesFileTest(); +DiagnosticsTest* MakeDiskSpaceTest(); +DiagnosticsTest* MakePreferencesTest(); +DiagnosticsTest* MakeBookMarksTest(); +DiagnosticsTest* MakeLocalStateTest(); + +} // namespace diagnostics #endif // CHROME_BROWSER_DIAGNOSTICS_RECON_DIAGNOSTICS_H_ diff --git a/chrome/browser/diagnostics/sqlite_diagnostics.cc b/chrome/browser/diagnostics/sqlite_diagnostics.cc index e808c5e..ed938d3 100644 --- a/chrome/browser/diagnostics/sqlite_diagnostics.cc +++ b/chrome/browser/diagnostics/sqlite_diagnostics.cc @@ -6,13 +6,17 @@ #include "base/file_util.h" #include "base/logging.h" +#include "base/memory/ref_counted.h" #include "base/memory/singleton.h" +#include "base/memory/weak_ptr.h" #include "base/metrics/histogram.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" +#include "chromeos/chromeos_constants.h" #include "components/webdata/common/webdata_constants.h" #include "content/public/common/content_constants.h" #include "sql/connection.h" @@ -21,68 +25,159 @@ #include "webkit/browser/database/database_tracker.h" #include "webkit/common/appcache/appcache_interfaces.h" +namespace diagnostics { + +const char kSQLiteIntegrityAppCacheTest[] = "SQLiteIntegrityAppCache"; +const char kSQLiteIntegrityArchivedHistoryTest[] = + "SQLiteIntegrityArchivedHistory"; +const char kSQLiteIntegrityCookieTest[] = "SQLiteIntegrityCookie"; +const char kSQLiteIntegrityDatabaseTrackerTest[] = + "SQLiteIntegrityDatabaseTracker"; +const char kSQLiteIntegrityHistoryTest[] = "SQLiteIntegrityHistory"; +const char kSQLiteIntegrityThumbnailsTest[] = "SQLiteIntegrityThumbnails"; +const char kSQLiteIntegrityWebTest[] = "SQLiteIntegrityWeb"; + +#if defined(OS_CHROMEOS) +const char kSQLiteIntegrityNSSCertTest[] = "SQLiteIntegrityNSSCert"; +const char kSQLiteIntegrityNSSKeyTest[] = "SQLiteIntegrityNSSKey"; +#endif + namespace { -// Generic diagnostic test class for checking sqlite db integrity. -class SqliteIntegrityTest : public DiagnosticTest { +// Generic diagnostic test class for checking SQLite database integrity. +class SqliteIntegrityTest : public DiagnosticsTest { public: - SqliteIntegrityTest(bool critical, const string16& title, - const base::FilePath& profile_relative_db_path) - : DiagnosticTest(title), - critical_(critical), - db_path_(profile_relative_db_path) { - } - virtual int GetId() OVERRIDE { return 0; } + SqliteIntegrityTest(bool critical, + const std::string& id, + const std::string& title, + const base::FilePath& db_path) + : DiagnosticsTest(id, title), critical_(critical), db_path_(db_path) {} virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) OVERRIDE { - base::FilePath path = GetUserDefaultProfileDir(); - path = path.Append(db_path_); + // If we're given an absolute path, use it. If not, then assume it's under + // the profile directory. + base::FilePath path; + if (!db_path_.IsAbsolute()) + path = GetUserDefaultProfileDir().Append(db_path_); + else + path = db_path_; + if (!file_util::PathExists(path)) { - RecordOutcome(ASCIIToUTF16("File not found"), - critical_ ? DiagnosticsModel::TEST_FAIL_CONTINUE : - DiagnosticsModel::TEST_OK); + if (critical_) { + RecordOutcome(DIAG_SQLITE_FILE_NOT_FOUND, + "File not found", + DiagnosticsModel::TEST_FAIL_CONTINUE); + } else { + RecordOutcome(DIAG_SQLITE_FILE_NOT_FOUND_OK, + "File not found (but that is OK)", + DiagnosticsModel::TEST_OK); + } return true; } int errors = 0; - { // This block scopes the lifetime of the db objects. - sql::Connection db; - db.set_exclusive_locking(); - if (!db.Open(path)) { - RecordFailure(ASCIIToUTF16("Cannot open DB. Possibly corrupted")); + { // Scope the statement and database so they close properly. + sql::Connection database; + database.set_exclusive_locking(); + scoped_refptr<ErrorRecorder> recorder(new ErrorRecorder); + + // Set the error callback so that we can get useful results in a debug + // build for a corrupted database. Without setting the error callback, + // sql::Connection will just DCHECK. + database.set_error_callback( + base::Bind(&SqliteIntegrityTest::ErrorRecorder::RecordSqliteError, + recorder->AsWeakPtr(), + &database)); + if (!database.Open(path)) { + RecordFailure(DIAG_SQLITE_CANNOT_OPEN_DB, + "Cannot open DB. Possibly corrupted"); return true; } - sql::Statement s(db.GetUniqueStatement("PRAGMA integrity_check;")); - if (!s.is_valid()) { - int error = db.GetErrorCode(); + if (recorder->has_error()) { + RecordFailure(DIAG_SQLITE_ERROR_HANDLER_CALLED, + recorder->FormatError()); + return true; + } + sql::Statement statement( + database.GetUniqueStatement("PRAGMA integrity_check;")); + if (recorder->has_error()) { + RecordFailure(DIAG_SQLITE_ERROR_HANDLER_CALLED, + recorder->FormatError()); + return true; + } + if (!statement.is_valid()) { + int error = database.GetErrorCode(); if (SQLITE_BUSY == error) { - RecordFailure(ASCIIToUTF16("DB locked by another process")); + RecordFailure(DIAG_SQLITE_DB_LOCKED, + "Database locked by another process"); } else { - string16 str(ASCIIToUTF16("Pragma failed. Error: ")); - str += base::IntToString16(error); - RecordFailure(str); + std::string str("Pragma failed. Error: "); + str += base::IntToString(error); + RecordFailure(DIAG_SQLITE_PRAGMA_FAILED, str); } return false; } - while (s.Step()) { - std::string result(s.ColumnString(0)); + + while (statement.Step()) { + std::string result(statement.ColumnString(0)); if ("ok" != result) ++errors; } + if (recorder->has_error()) { + RecordFailure(DIAG_SQLITE_ERROR_HANDLER_CALLED, + recorder->FormatError()); + return true; + } } + // All done. Report to the user. if (errors != 0) { - string16 str(ASCIIToUTF16("Database corruption detected :")); - str += base::IntToString16(errors) + ASCIIToUTF16(" errors"); - RecordFailure(str); + std::string str("Database corruption detected: "); + str += base::IntToString(errors) + " errors"; + RecordFailure(DIAG_SQLITE_DB_CORRUPTED, str); return true; } - RecordSuccess(ASCIIToUTF16("no corruption detected")); + RecordSuccess("No corruption detected"); return true; } private: + class ErrorRecorder : public base::RefCounted<ErrorRecorder>, + public base::SupportsWeakPtr<ErrorRecorder> { + public: + ErrorRecorder() : has_error_(false), sqlite_error_(0), last_errno_(0) {} + + void RecordSqliteError(sql::Connection* connection, + int sqlite_error, + sql::Statement* statement) { + has_error_ = true; + sqlite_error_ = sqlite_error; + last_errno_ = connection->GetLastErrno(); + message_ = connection->GetErrorMessage(); + } + + bool has_error() const { return has_error_; } + + std::string FormatError() { + return base::StringPrintf("SQLite error: %d, Last Errno: %d: %s", + sqlite_error_, + last_errno_, + message_.c_str()); + } + + private: + friend class base::RefCounted<ErrorRecorder>; + ~ErrorRecorder() {} + + bool has_error_; + int sqlite_error_; + int last_errno_; + std::string message_; + + DISALLOW_COPY_AND_ASSIGN(ErrorRecorder); + }; + bool critical_; base::FilePath db_path_; DISALLOW_COPY_AND_ASSIGN(SqliteIntegrityTest); @@ -90,44 +185,77 @@ class SqliteIntegrityTest : public DiagnosticTest { } // namespace -DiagnosticTest* MakeSqliteWebDbTest() { - return new SqliteIntegrityTest(true, ASCIIToUTF16("Web DB"), +DiagnosticsTest* MakeSqliteWebDbTest() { + return new SqliteIntegrityTest(true, + kSQLiteIntegrityWebTest, + "Web Database", base::FilePath(kWebDataFilename)); } -DiagnosticTest* MakeSqliteCookiesDbTest() { - return new SqliteIntegrityTest(true, ASCIIToUTF16("Cookies DB"), +DiagnosticsTest* MakeSqliteCookiesDbTest() { + return new SqliteIntegrityTest(true, + kSQLiteIntegrityCookieTest, + "Cookies Database", base::FilePath(chrome::kCookieFilename)); } -DiagnosticTest* MakeSqliteHistoryDbTest() { - return new SqliteIntegrityTest(true, ASCIIToUTF16("History DB"), +DiagnosticsTest* MakeSqliteHistoryDbTest() { + return new SqliteIntegrityTest(true, + kSQLiteIntegrityHistoryTest, + "History Database", base::FilePath(chrome::kHistoryFilename)); } -DiagnosticTest* MakeSqliteArchivedHistoryDbTest() { +DiagnosticsTest* MakeSqliteArchivedHistoryDbTest() { return new SqliteIntegrityTest( - false, ASCIIToUTF16("Archived History DB"), + false, + kSQLiteIntegrityArchivedHistoryTest, + "Archived History Database", base::FilePath(chrome::kArchivedHistoryFilename)); } -DiagnosticTest* MakeSqliteThumbnailsDbTest() { - return new SqliteIntegrityTest(false, ASCIIToUTF16("Thumbnails DB"), +DiagnosticsTest* MakeSqliteThumbnailsDbTest() { + return new SqliteIntegrityTest(false, + kSQLiteIntegrityThumbnailsTest, + "Thumbnails Database", base::FilePath(chrome::kThumbnailsFilename)); } -DiagnosticTest* MakeSqliteAppCacheDbTest() { +DiagnosticsTest* MakeSqliteAppCacheDbTest() { base::FilePath appcache_dir(content::kAppCacheDirname); base::FilePath appcache_db = appcache_dir.Append(appcache::kAppCacheDatabaseName); - return new SqliteIntegrityTest(false, ASCIIToUTF16("AppCache DB"), + return new SqliteIntegrityTest(false, + kSQLiteIntegrityAppCacheTest, + "Application Cache Database", appcache_db); } -DiagnosticTest* MakeSqliteWebDatabaseTrackerDbTest() { +DiagnosticsTest* MakeSqliteWebDatabaseTrackerDbTest() { base::FilePath databases_dir(webkit_database::kDatabaseDirectoryName); base::FilePath tracker_db = databases_dir.Append(webkit_database::kTrackerDatabaseFileName); - return new SqliteIntegrityTest(false, ASCIIToUTF16("DatabaseTracker DB"), + return new SqliteIntegrityTest(false, + kSQLiteIntegrityDatabaseTrackerTest, + "Database Tracker Database", tracker_db); } + +#if defined(OS_CHROMEOS) +DiagnosticsTest* MakeSqliteNssCertDbTest() { + base::FilePath home_dir = file_util::GetHomeDir(); + return new SqliteIntegrityTest(false, + kSQLiteIntegrityNSSCertTest, + "NSS Certificate Database", + home_dir.Append(chromeos::kNssCertDbPath)); +} + +DiagnosticsTest* MakeSqliteNssKeyDbTest() { + base::FilePath home_dir = file_util::GetHomeDir(); + return new SqliteIntegrityTest(false, + kSQLiteIntegrityNSSKeyTest, + "NSS Key Database", + home_dir.Append(chromeos::kNssKeyDbPath)); +} +#endif // defined(OS_CHROMEOS) +} // namespace diagnostics diff --git a/chrome/browser/diagnostics/sqlite_diagnostics.h b/chrome/browser/diagnostics/sqlite_diagnostics.h index 2017c4b..279dd5b 100644 --- a/chrome/browser/diagnostics/sqlite_diagnostics.h +++ b/chrome/browser/diagnostics/sqlite_diagnostics.h @@ -7,13 +7,46 @@ #include "chrome/browser/diagnostics/diagnostics_test.h" -// Factories for the db integrity tests we run in diagnostic mode. -DiagnosticTest* MakeSqliteWebDbTest(); -DiagnosticTest* MakeSqliteCookiesDbTest(); -DiagnosticTest* MakeSqliteHistoryDbTest(); -DiagnosticTest* MakeSqliteArchivedHistoryDbTest(); -DiagnosticTest* MakeSqliteThumbnailsDbTest(); -DiagnosticTest* MakeSqliteAppCacheDbTest(); -DiagnosticTest* MakeSqliteWebDatabaseTrackerDbTest(); +namespace diagnostics { + +enum SQLiteIntegrityOutcomeCode { + DIAG_SQLITE_SUCCESS, + DIAG_SQLITE_FILE_NOT_FOUND_OK, + DIAG_SQLITE_FILE_NOT_FOUND, + DIAG_SQLITE_ERROR_HANDLER_CALLED, + DIAG_SQLITE_CANNOT_OPEN_DB, + DIAG_SQLITE_DB_LOCKED, + DIAG_SQLITE_PRAGMA_FAILED, + DIAG_SQLITE_DB_CORRUPTED +}; + +extern const char kSQLiteIntegrityAppCacheTest[]; +extern const char kSQLiteIntegrityArchivedHistoryTest[]; +extern const char kSQLiteIntegrityCookieTest[]; +extern const char kSQLiteIntegrityDatabaseTrackerTest[]; +extern const char kSQLiteIntegrityHistoryTest[]; +extern const char kSQLiteIntegrityThumbnailsTest[]; +extern const char kSQLiteIntegrityWebTest[]; + +#if defined(OS_CHROMEOS) +extern const char kSQLiteIntegrityNSSCertTest[]; +extern const char kSQLiteIntegrityNSSKeyTest[]; +#endif + +// Factories for the database integrity tests we run in diagnostic mode. +DiagnosticsTest* MakeSqliteWebDbTest(); +DiagnosticsTest* MakeSqliteCookiesDbTest(); +DiagnosticsTest* MakeSqliteHistoryDbTest(); +DiagnosticsTest* MakeSqliteArchivedHistoryDbTest(); +DiagnosticsTest* MakeSqliteThumbnailsDbTest(); +DiagnosticsTest* MakeSqliteAppCacheDbTest(); +DiagnosticsTest* MakeSqliteWebDatabaseTrackerDbTest(); + +#if defined(OS_CHROMEOS) +DiagnosticsTest* MakeSqliteNssCertDbTest(); +DiagnosticsTest* MakeSqliteNssKeyDbTest(); +#endif // defined(OS_CHROMEOS) + +} // namespace diagnostics #endif // CHROME_BROWSER_DIAGNOSTICS_SQLITE_DIAGNOSTICS_H_ diff --git a/chrome/browser/history/text_database.cc b/chrome/browser/history/text_database.cc index b37073a..7353174 100644 --- a/chrome/browser/history/text_database.cc +++ b/chrome/browser/history/text_database.cc @@ -14,7 +14,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/browser/diagnostics/sqlite_diagnostics.h" #include "sql/statement.h" #include "sql/transaction.h" diff --git a/chrome/browser/history/thumbnail_database.cc b/chrome/browser/history/thumbnail_database.cc index ef5c439..da34646e 100644 --- a/chrome/browser/history/thumbnail_database.cc +++ b/chrome/browser/history/thumbnail_database.cc @@ -20,7 +20,6 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" -#include "chrome/browser/diagnostics/sqlite_diagnostics.h" #include "chrome/browser/history/history_publisher.h" #include "chrome/browser/history/top_sites.h" #include "chrome/browser/history/url_database.h" diff --git a/chrome/browser/history/top_sites_database.cc b/chrome/browser/history/top_sites_database.cc index ec0e1de..cf4220d 100644 --- a/chrome/browser/history/top_sites_database.cc +++ b/chrome/browser/history/top_sites_database.cc @@ -6,7 +6,6 @@ #include "base/memory/ref_counted.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" -#include "chrome/browser/diagnostics/sqlite_diagnostics.h" #include "chrome/browser/history/history_types.h" #include "chrome/browser/history/top_sites.h" #include "chrome/browser/history/top_sites_database.h" diff --git a/chrome/browser/net/sqlite_server_bound_cert_store.cc b/chrome/browser/net/sqlite_server_bound_cert_store.cc index fe28561..865d911 100644 --- a/chrome/browser/net/sqlite_server_bound_cert_store.cc +++ b/chrome/browser/net/sqlite_server_bound_cert_store.cc @@ -17,7 +17,6 @@ #include "base/strings/string_util.h" #include "base/threading/thread.h" #include "base/threading/thread_restrictions.h" -#include "chrome/browser/diagnostics/sqlite_diagnostics.h" #include "content/public/browser/browser_thread.h" #include "net/cert/x509_certificate.h" #include "net/cookies/cookie_util.h" diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index cf0f80e..4852808 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -451,12 +451,14 @@ 'browser/custom_home_pages_table_model.h', 'browser/defaults.cc', 'browser/defaults.h', - 'browser/diagnostics/diagnostics_main.cc', - 'browser/diagnostics/diagnostics_main.h', + 'browser/diagnostics/diagnostics_controller.cc', + 'browser/diagnostics/diagnostics_controller.h', 'browser/diagnostics/diagnostics_model.cc', 'browser/diagnostics/diagnostics_model.h', 'browser/diagnostics/diagnostics_test.cc', 'browser/diagnostics/diagnostics_test.h', + 'browser/diagnostics/diagnostics_writer.cc', + 'browser/diagnostics/diagnostics_writer.h', 'browser/diagnostics/recon_diagnostics.cc', 'browser/diagnostics/recon_diagnostics.h', 'browser/diagnostics/sqlite_diagnostics.cc', @@ -3000,6 +3002,7 @@ 'sources/': [ ['exclude', '^browser/captive_portal/'], ['exclude', '^browser/chrome_to_mobile'], + ['exclude', '^browser/diagnostics/'], ['exclude', '^browser/first_run/'], ['include', '^browser/first_run/first_run.cc'], # For ctor/dtor of a struct. ['exclude', '^browser/importer/'], diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index ff34e79..1a90cd9 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -2443,6 +2443,7 @@ 'sources/': [ ['exclude', '^browser/captive_portal/'], ['exclude', '^browser/chrome_to_mobile'], + ['exclude', '^browser/diagnostics/'], ['exclude', '^browser/first_run/'], ['exclude', '^browser/importer/'], ['exclude', '^browser/lifetime/'], diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 2453994..fbff304 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -259,6 +259,9 @@ const char kDeviceManagementUrl[] = "device-management-url"; // Triggers a plethora of diagnostic modes. const char kDiagnostics[] = "diagnostics"; +// Sets the output format for diagnostic modes enabled by diagnostics flag. +const char kDiagnosticsFormat[] = "diagnostics-format"; + // Replaces the audio IPC layer for <audio> and <video> with a mock audio // device, useful when using remote desktop or machines without sound cards. // This is temporary until we fix the underlying problem. diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index f1b9f9a..a320599 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -82,6 +82,7 @@ extern const char kDebugPackedApps[]; extern const char kDebugPrint[]; extern const char kDeviceManagementUrl[]; extern const char kDiagnostics[]; +extern const char kDiagnosticsFormat[]; extern const char kDisableAsyncDns[]; extern const char kDisableAuthNegotiateCnameLookup[]; extern const char kDisableBackgroundMode[]; diff --git a/chromeos/chromeos_constants.cc b/chromeos/chromeos_constants.cc index a8b58ae..52334b68 100644 --- a/chromeos/chromeos_constants.cc +++ b/chromeos/chromeos_constants.cc @@ -9,5 +9,7 @@ namespace chromeos { const base::FilePath::CharType kDriveCacheDirname[] = FPL("GCache"); +const base::FilePath::CharType kNssCertDbPath[] = FPL(".pki/nssdb/cert9.db"); +const base::FilePath::CharType kNssKeyDbPath[] = FPL(".pki/nssdb/key4.db"); } // namespace chromeos diff --git a/chromeos/chromeos_constants.h b/chromeos/chromeos_constants.h index ab3f2be..938ac84 100644 --- a/chromeos/chromeos_constants.h +++ b/chromeos/chromeos_constants.h @@ -13,6 +13,8 @@ namespace chromeos { CHROMEOS_EXPORT extern const base::FilePath::CharType kDriveCacheDirname[]; +CHROMEOS_EXPORT extern const base::FilePath::CharType kNssCertDbPath[]; +CHROMEOS_EXPORT extern const base::FilePath::CharType kNssKeyDbPath[]; } // namespace chromeos |