blob: 52f2ff0deedff9e4295a5bf87016113214787e00 [file] [log] [blame]
[email protected]1eeb5e02010-07-20 23:02:111// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]26f46472009-12-20 03:57:102// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]31a5d882010-02-05 04:01:085#include "chrome/browser/diagnostics/recon_diagnostics.h"
6
[email protected]1eeb5e02010-07-20 23:02:117#include <string>
8
[email protected]26f46472009-12-20 03:57:109#include "base/file_util.h"
[email protected]36e766962010-04-14 00:59:1710#include "base/json/json_reader.h"
[email protected]26f46472009-12-20 03:57:1011#include "base/string_util.h"
[email protected]528c56d2010-07-30 19:28:4412#include "base/string_number_conversions.h"
[email protected]4bf41352010-03-08 21:21:3613#include "base/utf_string_conversions.h"
[email protected]31a5d882010-02-05 04:01:0814#include "base/sys_info.h"
[email protected]26f46472009-12-20 03:57:1015#include "base/path_service.h"
16#include "chrome/browser/diagnostics/diagnostics_test.h"
[email protected]14a000d2010-04-29 21:44:2417#include "chrome/browser/platform_util.h"
[email protected]26f46472009-12-20 03:57:1018#include "chrome/common/chrome_paths.h"
[email protected]1eeb5e02010-07-20 23:02:1119#include "chrome/common/chrome_version_info.h"
[email protected]36e766962010-04-14 00:59:1720#include "chrome/common/json_value_serializer.h"
[email protected]26f46472009-12-20 03:57:1021
22#if defined(OS_WIN)
23#include "base/win_util.h"
24#include "chrome/installer/util/install_util.h"
25#endif
26
27// Reconnaissance diagnostics. These are the first and most critical
28// diagnostic tests. Here we check for the existence of critical files.
29// TODO(cpu): Define if it makes sense to localize strings.
30
[email protected]36e766962010-04-14 00:59:1731// TODO(cpu): There are a few maxium file sizes hardcoded in this file
32// that have little or no theoretical or experimental ground. Find a way
33// to justify them.
34
[email protected]26f46472009-12-20 03:57:1035namespace {
36
37class InstallTypeTest;
38InstallTypeTest* g_install_type = 0;
39
[email protected]31a5d882010-02-05 04:01:0840// Check that the flavor of the operating system is supported.
41class OperatingSystemTest : public DiagnosticTest {
[email protected]26f46472009-12-20 03:57:1042 public:
[email protected]31a5d882010-02-05 04:01:0843 OperatingSystemTest() : DiagnosticTest(ASCIIToUTF16("Operating System")) {}
[email protected]26f46472009-12-20 03:57:1044
45 virtual int GetId() { return 0; }
46
47 virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
[email protected]31a5d882010-02-05 04:01:0848 int version = 0;
49 int major = 0;
50 int minor = 0;
51#if defined(OS_WIN)
52 version = win_util::GetWinVersion();
[email protected]26f46472009-12-20 03:57:1053 if (version < win_util::WINVERSION_XP) {
54 RecordFailure(ASCIIToUTF16("Windows 2000 or earlier"));
55 return false;
56 }
[email protected]26f46472009-12-20 03:57:1057 win_util::GetServicePackLevel(&major, &minor);
58 if ((version == win_util::WINVERSION_XP) && (major < 2)) {
59 RecordFailure(ASCIIToUTF16("XP Service Pack 1 or earlier"));
60 return false;
61 }
[email protected]31a5d882010-02-05 04:01:0862#else
63 // TODO(port): define the OS criteria for linux and mac.
64#endif // defined(OS_WIN)
65 RecordSuccess(ASCIIToUTF16(StringPrintf("%s %s (%d [%d:%d])",
66 base::SysInfo::OperatingSystemName().c_str(),
67 base::SysInfo::OperatingSystemVersion().c_str(),
68 version, major, minor)));
[email protected]26f46472009-12-20 03:57:1069 return true;
70 }
71
72 private:
[email protected]31a5d882010-02-05 04:01:0873 DISALLOW_COPY_AND_ASSIGN(OperatingSystemTest);
[email protected]26f46472009-12-20 03:57:1074};
75
76// Check if it is system install or per-user install.
77class InstallTypeTest : public DiagnosticTest {
78 public:
79 InstallTypeTest() : DiagnosticTest(ASCIIToUTF16("Install Type")),
80 user_level_(false) {}
81
82 virtual int GetId() { return 0; }
83
84 virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
[email protected]31a5d882010-02-05 04:01:0885#if defined(OS_WIN)
[email protected]26f46472009-12-20 03:57:1086 FilePath chrome_exe;
87 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
88 RecordFailure(ASCIIToUTF16("Path provider failure"));
89 return false;
90 }
91 user_level_ = InstallUtil::IsPerUserInstall(
92 chrome_exe.ToWStringHack().c_str());
[email protected]31a5d882010-02-05 04:01:0893 const char* type = user_level_ ? "User Level" : "System Level";
94 string16 install_type(ASCIIToUTF16(type));
95#else
96 string16 install_type(ASCIIToUTF16("System Level"));
97#endif // defined(OS_WIN)
[email protected]26f46472009-12-20 03:57:1098 RecordSuccess(install_type);
99 g_install_type = this;
100 return true;
101 }
102
103 bool system_level() const { return !user_level_; }
104
105 private:
106 bool user_level_;
107 DISALLOW_COPY_AND_ASSIGN(InstallTypeTest);
108};
109
[email protected]31a5d882010-02-05 04:01:08110// Check the version of Chrome.
111class VersionTest : public DiagnosticTest {
[email protected]26f46472009-12-20 03:57:10112 public:
[email protected]31a5d882010-02-05 04:01:08113 VersionTest() : DiagnosticTest(ASCIIToUTF16("Browser Version")) {}
[email protected]26f46472009-12-20 03:57:10114
115 virtual int GetId() { return 0; }
116
117 virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
[email protected]0211f57e2010-08-27 20:28:42118 chrome::VersionInfo version_info;
119 if (!version_info.is_valid()) {
[email protected]31a5d882010-02-05 04:01:08120 RecordFailure(ASCIIToUTF16("No Version"));
121 return true;
122 }
[email protected]0211f57e2010-08-27 20:28:42123 std::string current_version = version_info.Version();
[email protected]31a5d882010-02-05 04:01:08124 if (current_version.empty()) {
125 RecordFailure(ASCIIToUTF16("Empty Version"));
126 return true;
127 }
[email protected]0211f57e2010-08-27 20:28:42128 std::string version_modifier = platform_util::GetVersionStringModifier();
129 if (!version_modifier.empty())
130 current_version += " " + version_modifier;
[email protected]31a5d882010-02-05 04:01:08131#if defined(GOOGLE_CHROME_BUILD)
[email protected]0211f57e2010-08-27 20:28:42132 current_version += " GCB";
[email protected]31a5d882010-02-05 04:01:08133#endif // defined(GOOGLE_CHROME_BUILD)
[email protected]0211f57e2010-08-27 20:28:42134 RecordSuccess(ASCIIToUTF16(current_version));
[email protected]26f46472009-12-20 03:57:10135 return true;
136 }
137
[email protected]26f46472009-12-20 03:57:10138 private:
[email protected]31a5d882010-02-05 04:01:08139 DISALLOW_COPY_AND_ASSIGN(VersionTest);
[email protected]26f46472009-12-20 03:57:10140};
[email protected]26f46472009-12-20 03:57:10141
142struct TestPathInfo {
143 const char* test_name;
[email protected]9f3c8492010-03-24 23:22:52144 int path_id;
145 bool is_directory;
146 bool is_optional;
[email protected]26f46472009-12-20 03:57:10147 bool test_writable;
[email protected]6d745ac2010-01-14 22:12:59148 int64 max_size;
[email protected]26f46472009-12-20 03:57:10149};
150
[email protected]6d745ac2010-01-14 22:12:59151const int64 kOneKilo = 1024;
152const int64 kOneMeg = 1024 * kOneKilo;
153
[email protected]26f46472009-12-20 03:57:10154const TestPathInfo kPathsToTest[] = {
[email protected]9f3c8492010-03-24 23:22:52155 {"User data Directory", chrome::DIR_USER_DATA,
[email protected]2d367ca2010-07-14 21:07:00156 true, false, true, 850 * kOneMeg},
[email protected]9f3c8492010-03-24 23:22:52157 {"Local state file", chrome::FILE_LOCAL_STATE,
[email protected]2d367ca2010-07-14 21:07:00158 false, false, true, 500 * kOneKilo},
[email protected]9f3c8492010-03-24 23:22:52159 {"Dictionaries Directory", chrome::DIR_APP_DICTIONARIES,
160 true, true, false, 0},
161 {"Inspector Directory", chrome::DIR_INSPECTOR,
162 true, false, false, 0}
[email protected]26f46472009-12-20 03:57:10163};
164
165// Check that the user's data directory exists and the paths are writeable.
166// If it is a systemwide install some paths are not expected to be writeable.
167// This test depends on |InstallTypeTest| having run succesfuly.
168class PathTest : public DiagnosticTest {
169 public:
170 explicit PathTest(const TestPathInfo& path_info)
171 : DiagnosticTest(ASCIIToUTF16(path_info.test_name)),
172 path_info_(path_info) {}
173
174 virtual int GetId() { return 0; }
175
176 virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
177 if (!g_install_type) {
178 RecordStopFailure(ASCIIToUTF16("dependency failure"));
179 return false;
180 }
[email protected]6d745ac2010-01-14 22:12:59181 FilePath dir_or_file;
[email protected]9f3c8492010-03-24 23:22:52182 if (!PathService::Get(path_info_.path_id, &dir_or_file)) {
[email protected]26f46472009-12-20 03:57:10183 RecordStopFailure(ASCIIToUTF16("Path provider failure"));
184 return false;
185 }
[email protected]6d745ac2010-01-14 22:12:59186 if (!file_util::PathExists(dir_or_file)) {
[email protected]26f46472009-12-20 03:57:10187 RecordFailure(ASCIIToUTF16("Path not found"));
188 return true;
189 }
[email protected]6d745ac2010-01-14 22:12:59190
[email protected]9f3c8492010-03-24 23:22:52191 int64 dir_or_file_size = 0;
192 if (path_info_.is_directory) {
193 dir_or_file_size = file_util::ComputeDirectorySize(dir_or_file);
194 } else {
195 file_util::GetFileSize(dir_or_file, &dir_or_file_size);
196 }
197 if (!dir_or_file_size && !path_info_.is_optional) {
[email protected]6d745ac2010-01-14 22:12:59198 RecordFailure(ASCIIToUTF16("Cannot obtain size"));
199 return true;
200 }
201 DataUnits units = GetByteDisplayUnits(dir_or_file_size);
[email protected]7b83a102010-08-19 23:11:28202 string16 printable_size = FormatBytes(dir_or_file_size, units, true);
[email protected]6d745ac2010-01-14 22:12:59203
204 if (path_info_.max_size > 0) {
205 if (dir_or_file_size > path_info_.max_size) {
206 RecordFailure(ASCIIToUTF16("Path is too big: ") + printable_size);
207 return true;
208 }
209 }
[email protected]26f46472009-12-20 03:57:10210 if (g_install_type->system_level() && !path_info_.test_writable) {
211 RecordSuccess(ASCIIToUTF16("Path exists"));
212 return true;
213 }
[email protected]6d745ac2010-01-14 22:12:59214 if (!file_util::PathIsWritable(dir_or_file)) {
[email protected]26f46472009-12-20 03:57:10215 RecordFailure(ASCIIToUTF16("Path is not writable"));
216 return true;
217 }
[email protected]31a5d882010-02-05 04:01:08218 RecordSuccess(ASCIIToUTF16("Path exists and is writable: ")
219 + printable_size);
[email protected]26f46472009-12-20 03:57:10220 return true;
221 }
222
223 private:
224 TestPathInfo path_info_;
225 DISALLOW_COPY_AND_ASSIGN(PathTest);
226};
227
[email protected]31a5d882010-02-05 04:01:08228// Check that the disk space in the volume where the user data dir normally
229// lives is not dangerosly low.
230class DiskSpaceTest : public DiagnosticTest {
231 public:
232 DiskSpaceTest() : DiagnosticTest(ASCIIToUTF16("Disk Space")) {}
233
234 virtual int GetId() { return 0; }
235
236 virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
237 FilePath data_dir;
238 if (!PathService::Get(chrome::DIR_USER_DATA, &data_dir))
239 return false;
240 int64 disk_space = base::SysInfo::AmountOfFreeDiskSpace(data_dir);
241 if (disk_space < 0) {
242 RecordFailure(ASCIIToUTF16("Unable to query free space"));
243 return true;
244 }
245 DataUnits units = GetByteDisplayUnits(disk_space);
[email protected]7b83a102010-08-19 23:11:28246 string16 printable_size = FormatBytes(disk_space, units, true);
[email protected]31a5d882010-02-05 04:01:08247 if (disk_space < 80 * kOneMeg) {
248 RecordFailure(ASCIIToUTF16("Low disk space : ") + printable_size);
249 return true;
250 }
251 RecordSuccess(ASCIIToUTF16("Free space : ") + printable_size);
252 return true;
253 }
254
255 private:
256 DISALLOW_COPY_AND_ASSIGN(DiskSpaceTest);
257};
258
[email protected]36e766962010-04-14 00:59:17259// Checks that a given json file can be correctly parsed.
260class JSONTest : public DiagnosticTest {
261 public:
262 JSONTest(const FilePath& path, const string16 name, int64 max_file_size)
263 : DiagnosticTest(name), path_(path), max_file_size_(max_file_size) {
264 }
265
266 virtual int GetId() { return 0; }
267
268 virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
269 if (!file_util::PathExists(path_)) {
270 RecordFailure(ASCIIToUTF16("File not found"));
271 return true;
272 }
273 int64 file_size;
274 file_util::GetFileSize(path_, &file_size);
275 if (file_size > max_file_size_) {
276 RecordFailure(ASCIIToUTF16("File too big"));
277 return true;
278 }
279 // Being small enough, we can process it in-memory.
280 std::string json_data;
281 if (!file_util::ReadFileToString(path_, &json_data)) {
282 RecordFailure(ASCIIToUTF16(
283 "Could not open file. Possibly locked by other process"));
284 return true;
285 }
286
287 JSONStringValueSerializer json(json_data);
288 int error_code = base::JSONReader::JSON_NO_ERROR;
289 std::string error_message;
290 scoped_ptr<Value> json_root(json.Deserialize(&error_code, &error_message));
291 if (base::JSONReader::JSON_NO_ERROR != error_code) {
292 if (error_message.empty()) {
[email protected]528c56d2010-07-30 19:28:44293 error_message = "Parse error " + base::IntToString(error_code);
[email protected]36e766962010-04-14 00:59:17294 }
295 RecordFailure(UTF8ToUTF16(error_message));
296 return true;
297 }
298
299 RecordSuccess(ASCIIToUTF16("File parsed OK"));
300 return true;
301 }
302
303 private:
304 FilePath path_;
305 int64 max_file_size_;
306 DISALLOW_COPY_AND_ASSIGN(JSONTest);
307};
308
[email protected]26f46472009-12-20 03:57:10309} // namespace
310
311DiagnosticTest* MakeUserDirTest() {
312 return new PathTest(kPathsToTest[0]);
313}
314
315DiagnosticTest* MakeLocalStateFileTest() {
316 return new PathTest(kPathsToTest[1]);
317}
318
[email protected]31a5d882010-02-05 04:01:08319DiagnosticTest* MakeDictonaryDirTest() {
[email protected]26f46472009-12-20 03:57:10320 return new PathTest(kPathsToTest[2]);
321}
322
[email protected]31a5d882010-02-05 04:01:08323DiagnosticTest* MakeInspectorDirTest() {
[email protected]26f46472009-12-20 03:57:10324 return new PathTest(kPathsToTest[3]);
325}
326
[email protected]31a5d882010-02-05 04:01:08327DiagnosticTest* MakeVersionTest() {
328 return new VersionTest();
[email protected]26f46472009-12-20 03:57:10329}
330
[email protected]31a5d882010-02-05 04:01:08331DiagnosticTest* MakeDiskSpaceTest() {
332 return new DiskSpaceTest();
[email protected]26f46472009-12-20 03:57:10333}
[email protected]31a5d882010-02-05 04:01:08334
335DiagnosticTest* MakeOperatingSystemTest() {
336 return new OperatingSystemTest();
337}
[email protected]26f46472009-12-20 03:57:10338
339DiagnosticTest* MakeInstallTypeTest() {
340 return new InstallTypeTest();
341}
342
[email protected]36e766962010-04-14 00:59:17343DiagnosticTest* MakePreferencesTest() {
344 FilePath path = DiagnosticTest::GetUserDefaultProfileDir();
345 path = path.Append(chrome::kPreferencesFilename);
346 return new JSONTest(path, ASCIIToUTF16("Profile JSON"), 100 * kOneKilo);
347}
348
349DiagnosticTest* MakeBookMarksTest() {
350 FilePath path = DiagnosticTest::GetUserDefaultProfileDir();
351 path = path.Append(chrome::kBookmarksFileName);
352 return new JSONTest(path, ASCIIToUTF16("BookMarks JSON"), 2 * kOneMeg);
353}
354
355DiagnosticTest* MakeLocalStateTest() {
356 FilePath path;
357 PathService::Get(chrome::DIR_USER_DATA, &path);
358 path = path.Append(chrome::kLocalStateFilename);
359 return new JSONTest(path, ASCIIToUTF16("Local State JSON"), 50 * kOneKilo);
360}