1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "app/sql/connection.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/sql/diagnostic_error_delegate.h"
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "app/sql/statement.h"
1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/file_util.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/memory/singleton.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/metrics/histogram.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h"
15731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/string_number_conversions.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
173f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "chrome/common/chrome_constants.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/chrome_paths.h"
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "third_party/sqlite/sqlite3.h"
2021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "webkit/appcache/appcache_interfaces.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "webkit/database/database_tracker.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Generic diagnostic test class for checking sqlite db integrity.
264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochclass SqliteIntegrityTest : public DiagnosticTest {
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen public:
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SqliteIntegrityTest(bool critical, const string16& title,
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                      const FilePath& profile_relative_db_path)
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : DiagnosticTest(title),
31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        critical_(critical),
32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        db_path_(profile_relative_db_path) {
33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual int GetId() { return 0; }
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FilePath path = GetUserDefaultProfileDir();
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    path = path.Append(db_path_);
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!file_util::PathExists(path)) {
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      RecordOutcome(ASCIIToUTF16("File not found"),
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    critical_ ? DiagnosticsModel::TEST_FAIL_CONTINUE :
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                DiagnosticsModel::TEST_OK);
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int errors = 0;
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { // This block scopes the lifetime of the db objects.
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      sql::Connection db;
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      db.set_exclusive_locking();
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!db.Open(path)) {
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RecordFailure(ASCIIToUTF16("Cannot open DB. Possibly corrupted"));
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return true;
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      sql::Statement s(db.GetUniqueStatement("PRAGMA integrity_check;"));
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!s) {
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        int error = db.GetErrorCode();
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (SQLITE_BUSY == error) {
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          RecordFailure(ASCIIToUTF16("DB locked by another process"));
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        } else {
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          string16 str(ASCIIToUTF16("Pragma failed. Error: "));
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          str += base::IntToString16(error);
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          RecordFailure(str);
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      while (s.Step()) {
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::string result(s.ColumnString(0));
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if ("ok" != result)
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ++errors;
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // All done. Report to the user.
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (errors != 0) {
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      string16 str(ASCIIToUTF16("Database corruption detected :"));
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      str += base::IntToString16(errors) + ASCIIToUTF16(" errors");
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      RecordFailure(str);
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    RecordSuccess(ASCIIToUTF16("no corruption detected"));
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool critical_;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath db_path_;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(SqliteIntegrityTest);
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Uniquifier to use the sql::DiagnosticErrorDelegate template which
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// requires a static name() method.
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtemplate <size_t unique>
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass HistogramUniquifier {
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const char* name() {
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* kHistogramNames[] = {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sqlite.Cookie.Error",
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sqlite.History.Error",
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sqlite.Thumbnail.Error",
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sqlite.Text.Error",
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sqlite.Web.Error"
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return kHistogramNames[unique];
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsql::ErrorDelegate* GetErrorHandlerForCookieDb() {
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new sql::DiagnosticErrorDelegate<HistogramUniquifier<0> >();
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsql::ErrorDelegate* GetErrorHandlerForHistoryDb() {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new sql::DiagnosticErrorDelegate<HistogramUniquifier<1> >();
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsql::ErrorDelegate* GetErrorHandlerForThumbnailDb() {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new sql::DiagnosticErrorDelegate<HistogramUniquifier<2> >();
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsql::ErrorDelegate* GetErrorHandlerForTextDb() {
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new sql::DiagnosticErrorDelegate<HistogramUniquifier<3> >();
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsql::ErrorDelegate* GetErrorHandlerForWebDb() {
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new sql::DiagnosticErrorDelegate<HistogramUniquifier<4> >();
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDiagnosticTest* MakeSqliteWebDbTest() {
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new SqliteIntegrityTest(true, ASCIIToUTF16("Web DB"),
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 FilePath(chrome::kWebDataFilename));
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDiagnosticTest* MakeSqliteCookiesDbTest() {
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new SqliteIntegrityTest(true, ASCIIToUTF16("Cookies DB"),
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 FilePath(chrome::kCookieFilename));
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDiagnosticTest* MakeSqliteHistoryDbTest() {
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new SqliteIntegrityTest(true, ASCIIToUTF16("History DB"),
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 FilePath(chrome::kHistoryFilename));
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDiagnosticTest* MakeSqliteArchivedHistoryDbTest() {
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new SqliteIntegrityTest(false, ASCIIToUTF16("Archived History DB"),
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 FilePath(chrome::kArchivedHistoryFilename));
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDiagnosticTest* MakeSqliteThumbnailsDbTest() {
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new SqliteIntegrityTest(false, ASCIIToUTF16("Thumbnails DB"),
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 FilePath(chrome::kThumbnailsFilename));
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDiagnosticTest* MakeSqliteAppCacheDbTest() {
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath appcache_dir(chrome::kAppCacheDirname);
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath appcache_db = appcache_dir.Append(appcache::kAppCacheDatabaseName);
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new SqliteIntegrityTest(false, ASCIIToUTF16("AppCache DB"),
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 appcache_db);
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDiagnosticTest* MakeSqliteWebDatabaseTrackerDbTest() {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath databases_dir(webkit_database::kDatabaseDirectoryName);
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath tracker_db =
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      databases_dir.Append(webkit_database::kTrackerDatabaseFileName);
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new SqliteIntegrityTest(false, ASCIIToUTF16("DatabaseTracker DB"),
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 tracker_db);
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch