Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(587)

Side by Side Diff: chrome/browser/chromeos/boot_times_loader.cc

Issue 303233004: Write "logout-started" event on next boot. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add exception for ScopedAllowIO. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/boot_times_loader.h" 5 #include "chrome/browser/chromeos/boot_times_loader.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/file_util.h" 11 #include "base/file_util.h"
12 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
13 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
14 #include "base/location.h" 16 #include "base/location.h"
15 #include "base/message_loop/message_loop.h" 17 #include "base/message_loop/message_loop.h"
16 #include "base/message_loop/message_loop_proxy.h" 18 #include "base/message_loop/message_loop_proxy.h"
17 #include "base/metrics/histogram.h" 19 #include "base/metrics/histogram.h"
20 #include "base/prefs/pref_service.h"
18 #include "base/strings/string_number_conversions.h" 21 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h" 22 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h" 23 #include "base/strings/stringprintf.h"
21 #include "base/threading/thread.h" 24 #include "base/threading/thread.h"
22 #include "base/threading/thread_restrictions.h" 25 #include "base/threading/thread_restrictions.h"
23 #include "base/time/time.h" 26 #include "base/time/time.h"
24 #include "chrome/browser/browser_process.h" 27 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/chrome_notification_types.h" 28 #include "chrome/browser/chrome_notification_types.h"
26 #include "chrome/browser/chromeos/login/auth/authentication_notification_details .h" 29 #include "chrome/browser/chromeos/login/auth/authentication_notification_details .h"
27 #include "chrome/browser/chromeos/login/users/user_manager.h" 30 #include "chrome/browser/chromeos/login/users/user_manager.h"
28 #include "chrome/browser/ui/browser.h" 31 #include "chrome/browser/ui/browser.h"
29 #include "chrome/browser/ui/browser_iterator.h" 32 #include "chrome/browser/ui/browser_iterator.h"
30 #include "chrome/browser/ui/tabs/tab_strip_model.h" 33 #include "chrome/browser/ui/tabs/tab_strip_model.h"
31 #include "chrome/common/chrome_switches.h" 34 #include "chrome/common/chrome_switches.h"
35 #include "chrome/common/pref_names.h"
32 #include "content/public/browser/browser_thread.h" 36 #include "content/public/browser/browser_thread.h"
33 #include "content/public/browser/navigation_controller.h" 37 #include "content/public/browser/navigation_controller.h"
34 #include "content/public/browser/notification_service.h" 38 #include "content/public/browser/notification_service.h"
35 #include "content/public/browser/render_widget_host_view.h" 39 #include "content/public/browser/render_widget_host_view.h"
36 #include "content/public/browser/web_contents.h" 40 #include "content/public/browser/web_contents.h"
37 41
38 using content::BrowserThread; 42 using content::BrowserThread;
39 using content::NavigationController; 43 using content::NavigationController;
40 using content::RenderWidgetHost; 44 using content::RenderWidgetHost;
41 using content::RenderWidgetHostView; 45 using content::RenderWidgetHostView;
42 using content::WebContents; 46 using content::WebContents;
43 47
44 namespace { 48 namespace {
45 49
50 const char kUptime[] = "uptime";
51 const char kDisk[] = "disk";
52
46 RenderWidgetHost* GetRenderWidgetHost(NavigationController* tab) { 53 RenderWidgetHost* GetRenderWidgetHost(NavigationController* tab) {
47 WebContents* web_contents = tab->GetWebContents(); 54 WebContents* web_contents = tab->GetWebContents();
48 if (web_contents) { 55 if (web_contents) {
49 RenderWidgetHostView* render_widget_host_view = 56 RenderWidgetHostView* render_widget_host_view =
50 web_contents->GetRenderWidgetHostView(); 57 web_contents->GetRenderWidgetHostView();
51 if (render_widget_host_view) 58 if (render_widget_host_view)
52 return render_widget_host_view->GetRenderWidgetHost(); 59 return render_widget_host_view->GetRenderWidgetHost();
53 } 60 }
54 return NULL; 61 return NULL;
55 } 62 }
56 63
57 const std::string GetTabUrl(RenderWidgetHost* rwh) { 64 const std::string GetTabUrl(RenderWidgetHost* rwh) {
58 RenderWidgetHostView* rwhv = rwh->GetView(); 65 RenderWidgetHostView* rwhv = rwh->GetView();
59 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 66 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
60 Browser* browser = *it; 67 Browser* browser = *it;
61 for (int i = 0, tab_count = browser->tab_strip_model()->count(); 68 for (int i = 0, tab_count = browser->tab_strip_model()->count();
62 i < tab_count; 69 i < tab_count;
63 ++i) { 70 ++i) {
64 WebContents* tab = browser->tab_strip_model()->GetWebContentsAt(i); 71 WebContents* tab = browser->tab_strip_model()->GetWebContentsAt(i);
65 if (tab->GetRenderWidgetHostView() == rwhv) { 72 if (tab->GetRenderWidgetHostView() == rwhv) {
66 return tab->GetLastCommittedURL().spec(); 73 return tab->GetLastCommittedURL().spec();
67 } 74 }
68 } 75 }
69 } 76 }
70 return std::string(); 77 return std::string();
71 } 78 }
72 79
80 // Appends the given buffer into the file. Returns the number of bytes
81 // written, or -1 on error.
82 // TODO(satorux): Move this to file_util.
83 int AppendFile(const base::FilePath& file_path, const char* data, int size) {
84 FILE* file = base::OpenFile(file_path, "a");
85 if (!file)
86 return -1;
87
88 const int num_bytes_written = fwrite(data, 1, size, file);
89 base::CloseFile(file);
90 return num_bytes_written;
91 }
92
73 } // namespace 93 } // namespace
74 94
75 namespace chromeos { 95 namespace chromeos {
76 96
77 #define FPL(value) FILE_PATH_LITERAL(value) 97 #define FPL(value) FILE_PATH_LITERAL(value)
78 98
79 // Dir uptime & disk logs are located in. 99 // Dir uptime & disk logs are located in.
80 static const base::FilePath::CharType kLogPath[] = FPL("/tmp"); 100 static const base::FilePath::CharType kLogPath[] = FPL("/tmp");
81 // Dir log{in,out} logs are located in. 101 // Dir log{in,out} logs are located in.
82 static const base::FilePath::CharType kLoginLogPath[] = 102 static const base::FilePath::CharType kLoginLogPath[] =
(...skipping 22 matching lines...) Expand all
105 125
106 // Name of file collecting login times. 126 // Name of file collecting login times.
107 static const base::FilePath::CharType kLoginTimes[] = FPL("login-times"); 127 static const base::FilePath::CharType kLoginTimes[] = FPL("login-times");
108 128
109 // Name of file collecting logout times. 129 // Name of file collecting logout times.
110 static const char kLogoutTimes[] = "logout-times"; 130 static const char kLogoutTimes[] = "logout-times";
111 131
112 static base::LazyInstance<BootTimesLoader> g_boot_times_loader = 132 static base::LazyInstance<BootTimesLoader> g_boot_times_loader =
113 LAZY_INSTANCE_INITIALIZER; 133 LAZY_INSTANCE_INITIALIZER;
114 134
115 BootTimesLoader::BootTimesLoader() 135 // static
116 : backend_(new Backend()), 136 BootTimesLoader::Stats BootTimesLoader::Stats::GetCurrentStats() {
117 have_registered_(false), 137 const base::FilePath kProcUptime(FPL("/proc/uptime"));
118 login_done_(false), 138 const base::FilePath kDiskStat(FPL("/sys/block/sda/stat"));
119 restart_requested_(false) { 139 Stats stats;
120 login_time_markers_.reserve(30); 140 // Callers of this method expect synchronous behavior.
121 logout_time_markers_.reserve(30); 141 // It's safe to allow IO here, because only virtual FS are accessed.
142 base::ThreadRestrictions::ScopedAllowIO allow_io;
143 base::ReadFileToString(kProcUptime, &stats.uptime_);
144 base::ReadFileToString(kDiskStat, &stats.disk_);
145 return stats;
122 } 146 }
123 147
124 BootTimesLoader::~BootTimesLoader() {} 148 std::string BootTimesLoader::Stats::SerializeToString() const {
149 if (uptime_.empty() || disk_.empty())
150 return std::string();
151 base::DictionaryValue dictionary;
152 dictionary.SetString(kUptime, uptime_);
153 dictionary.SetString(kDisk, disk_);
154
155 std::string result;
156 if (!base::JSONWriter::Write(&dictionary, &result)) {
157 LOG(WARNING) << "BootTimesLoader::Stats::SerializeToString(): failed.";
158 return std::string();
159 }
160
161 return result;
162 }
125 163
126 // static 164 // static
127 BootTimesLoader* BootTimesLoader::Get() { 165 BootTimesLoader::Stats BootTimesLoader::Stats::DeserializeFromString(
128 return g_boot_times_loader.Pointer(); 166 const std::string& source) {
167 if (source.empty())
168 return Stats();
169
170 scoped_ptr<base::Value> value(base::JSONReader::Read(source));
171 base::DictionaryValue* dictionary;
172 if (!value || !value->GetAsDictionary(&dictionary)) {
173 LOG(ERROR) << "BootTimesLoader::Stats::DeserializeFromString(): not a "
174 "dictionary: '" << source << "'";
175 return Stats();
176 }
177
178 Stats result;
179 if (!dictionary->GetString(kUptime, &result.uptime_) ||
180 !dictionary->GetString(kDisk, &result.disk_)) {
181 LOG(ERROR)
182 << "BootTimesLoader::Stats::DeserializeFromString(): format error: '"
183 << source << "'";
184 return Stats();
185 }
186
187 return result;
129 } 188 }
130 189
131 // Appends the given buffer into the file. Returns the number of bytes 190 bool BootTimesLoader::Stats::UptimeDouble(double* result) const {
132 // written, or -1 on error. 191 std::string uptime = uptime_;
133 // TODO(satorux): Move this to file_util. 192 const size_t space_at = uptime.find_first_of(' ');
134 static int AppendFile(const base::FilePath& file_path, 193 if (space_at == std::string::npos)
135 const char* data, 194 return false;
136 int size) { 195
137 FILE* file = base::OpenFile(file_path, "a"); 196 uptime.resize(space_at);
138 if (!file) { 197
139 return -1; 198 if (base::StringToDouble(uptime, result))
140 } 199 return true;
141 const int num_bytes_written = fwrite(data, 1, size, file); 200
142 base::CloseFile(file); 201 return false;
143 return num_bytes_written;
144 } 202 }
145 203
146 static void RecordStatsDelayed(const base::FilePath::StringType& name, 204 void BootTimesLoader::Stats::RecordStats(const std::string& name) const {
147 const std::string& uptime, 205 BrowserThread::PostBlockingPoolTask(
148 const std::string& disk) { 206 FROM_HERE,
207 base::Bind(&BootTimesLoader::Stats::RecordStatsImpl,
208 base::Owned(new Stats(*this)),
209 name));
210 }
211
212 void BootTimesLoader::Stats::RecordStatsWithCallback(
213 const std::string& name,
214 const base::Closure& callback) const {
215 BrowserThread::PostBlockingPoolTaskAndReply(
216 FROM_HERE,
217 base::Bind(&BootTimesLoader::Stats::RecordStatsImpl,
218 base::Owned(new Stats(*this)),
219 name),
220 callback);
221 }
222
223 void BootTimesLoader::Stats::RecordStatsImpl(
224 const base::FilePath::StringType& name) const {
225 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
226
149 const base::FilePath log_path(kLogPath); 227 const base::FilePath log_path(kLogPath);
150 const base::FilePath uptime_output = 228 const base::FilePath uptime_output =
151 log_path.Append(base::FilePath(kUptimePrefix + name)); 229 log_path.Append(base::FilePath(kUptimePrefix + name));
152 const base::FilePath disk_output = 230 const base::FilePath disk_output =
153 log_path.Append(base::FilePath(kDiskPrefix + name)); 231 log_path.Append(base::FilePath(kDiskPrefix + name));
154 232
155 // Append numbers to the files. 233 // Append numbers to the files.
156 AppendFile(uptime_output, uptime.data(), uptime.size()); 234 AppendFile(uptime_output, uptime_.data(), uptime_.size());
157 AppendFile(disk_output, disk.data(), disk.size()); 235 AppendFile(disk_output, disk_.data(), disk_.size());
236 }
237
238 BootTimesLoader::BootTimesLoader()
239 : backend_(new Backend()),
240 have_registered_(false),
241 login_done_(false),
242 restart_requested_(false) {
243 login_time_markers_.reserve(30);
244 logout_time_markers_.reserve(30);
245 }
246
247 BootTimesLoader::~BootTimesLoader() {
158 } 248 }
159 249
160 // static 250 // static
251 BootTimesLoader* BootTimesLoader::Get() {
252 return g_boot_times_loader.Pointer();
253 }
254
255 // static
161 void BootTimesLoader::WriteTimes( 256 void BootTimesLoader::WriteTimes(
162 const std::string base_name, 257 const std::string base_name,
163 const std::string uma_name, 258 const std::string uma_name,
164 const std::string uma_prefix, 259 const std::string uma_prefix,
165 std::vector<TimeMarker> login_times) { 260 std::vector<TimeMarker> login_times) {
166 const int kMinTimeMillis = 1; 261 const int kMinTimeMillis = 1;
167 const int kMaxTimeMillis = 30000; 262 const int kMaxTimeMillis = 30000;
168 const int kNumBuckets = 100; 263 const int kNumBuckets = 100;
169 const base::FilePath log_path(kLoginLogPath); 264 const base::FilePath log_path(kLoginLogPath);
170 265
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 // has already been terminated. 353 // has already been terminated.
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || 354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
260 !BrowserThread::IsMessageLoopValid(BrowserThread::UI)); 355 !BrowserThread::IsMessageLoopValid(BrowserThread::UI));
261 356
262 WriteTimes(kLogoutTimes, 357 WriteTimes(kLogoutTimes,
263 (restart_requested_ ? kUmaRestart : kUmaLogout), 358 (restart_requested_ ? kUmaRestart : kUmaLogout),
264 kUmaLogoutPrefix, 359 kUmaLogoutPrefix,
265 logout_time_markers_); 360 logout_time_markers_);
266 } 361 }
267 362
268 void BootTimesLoader::RecordStats(const std::string& name, const Stats& stats) { 363 // static
269 BrowserThread::PostTask( 364 void BootTimesLoader::ClearLogoutStartedLastPreference() {
270 BrowserThread::FILE, FROM_HERE, 365 PrefService* local_state = g_browser_process->local_state();
271 base::Bind(&RecordStatsDelayed, name, stats.uptime, stats.disk)); 366 local_state->ClearPref(prefs::kLogoutStartedLast);
272 } 367 }
273 368
274 BootTimesLoader::Stats BootTimesLoader::GetCurrentStats() { 369 void BootTimesLoader::OnChromeProcessStart() {
275 const base::FilePath kProcUptime(FPL("/proc/uptime")); 370 PrefService* local_state = g_browser_process->local_state();
276 const base::FilePath kDiskStat(FPL("/sys/block/sda/stat")); 371 const std::string logout_started_last_str =
277 Stats stats; 372 local_state->GetString(prefs::kLogoutStartedLast);
278 base::ThreadRestrictions::ScopedAllowIO allow_io; 373 if (logout_started_last_str.empty())
279 base::ReadFileToString(kProcUptime, &stats.uptime); 374 return;
280 base::ReadFileToString(kDiskStat, &stats.disk); 375
281 return stats; 376 // Note that kLogoutStartedLast is not cleared on format error to stay in
377 // logs in case of other fatal system errors.
378
379 const Stats logout_started_last_stats =
380 Stats::DeserializeFromString(logout_started_last_str);
381 if (logout_started_last_stats.uptime().empty())
382 return;
383
384 double logout_started_last;
385 double uptime;
386 if (!logout_started_last_stats.UptimeDouble(&logout_started_last) ||
387 !Stats::GetCurrentStats().UptimeDouble(&uptime)) {
388 return;
389 }
390
391 if (logout_started_last >= uptime) {
392 // Reboot happened.
393 ClearLogoutStartedLastPreference();
394 return;
395 }
396
397 // Write /tmp/uptime-logout-started as well.
398 const char kLogoutStarted[] = "logout-started";
399 logout_started_last_stats.RecordStatsWithCallback(
400 kLogoutStarted,
401 base::Bind(&BootTimesLoader::ClearLogoutStartedLastPreference));
402 }
403
404 void BootTimesLoader::OnLogoutStarted(PrefService* state) {
405 const std::string uptime = Stats::GetCurrentStats().SerializeToString();
406 if (!uptime.empty())
407 state->SetString(prefs::kLogoutStartedLast, uptime);
282 } 408 }
283 409
284 void BootTimesLoader::RecordCurrentStats(const std::string& name) { 410 void BootTimesLoader::RecordCurrentStats(const std::string& name) {
285 RecordStats(name, GetCurrentStats()); 411 Stats::GetCurrentStats().RecordStats(name);
286 } 412 }
287 413
288 void BootTimesLoader::SaveChromeMainStats() { 414 void BootTimesLoader::SaveChromeMainStats() {
289 chrome_main_stats_ = GetCurrentStats(); 415 chrome_main_stats_ = Stats::GetCurrentStats();
290 } 416 }
291 417
292 void BootTimesLoader::RecordChromeMainStats() { 418 void BootTimesLoader::RecordChromeMainStats() {
293 RecordStats(kChromeMain, chrome_main_stats_); 419 chrome_main_stats_.RecordStats(kChromeMain);
294 } 420 }
295 421
296 void BootTimesLoader::RecordLoginAttempted() { 422 void BootTimesLoader::RecordLoginAttempted() {
297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
298 if (login_done_) 424 if (login_done_)
299 return; 425 return;
300 426
301 login_time_markers_.clear(); 427 login_time_markers_.clear();
302 AddLoginTimeMarker("LoginStarted", false); 428 AddLoginTimeMarker("LoginStarted", false);
303 if (!have_registered_) { 429 if (!have_registered_) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 GetRenderWidgetHost(&web_contents->GetController()); 524 GetRenderWidgetHost(&web_contents->GetController());
399 render_widget_hosts_loading_.erase(render_widget_host); 525 render_widget_hosts_loading_.erase(render_widget_host);
400 break; 526 break;
401 } 527 }
402 default: 528 default:
403 break; 529 break;
404 } 530 }
405 } 531 }
406 532
407 } // namespace chromeos 533 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/boot_times_loader.h ('k') | chrome/browser/chromeos/chrome_browser_main_chromeos.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698