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

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: Remove duplicate lines. 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 }
stevenjb 2014/06/02 15:30:31 nit: {} unnecessary
Alexander Alekseev 2014/06/02 18:46:03 Done.
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 base::ThreadRestrictions::ScopedAllowIO allow_io;
stevenjb 2014/06/02 15:30:31 We should avoid using ScopedAllowIO if at all poss
Alexander Alekseev 2014/06/02 18:46:03 Done.
121 logout_time_markers_.reserve(30); 141 base::ReadFileToString(kProcUptime, &stats.uptime_);
142 base::ReadFileToString(kDiskStat, &stats.disk_);
143 return stats;
122 } 144 }
123 145
124 BootTimesLoader::~BootTimesLoader() {} 146 std::string BootTimesLoader::Stats::SerializeToString() const {
147 if (uptime_.empty() || disk_.empty())
148 return std::string();
149 base::DictionaryValue dictionary;
150 dictionary.SetString(kUptime, uptime_);
151 dictionary.SetString(kDisk, disk_);
152
153 std::string result;
154 if (!base::JSONWriter::Write(&dictionary, &result))
155 return std::string();
stevenjb 2014/06/02 15:30:31 nit: Should probably log an error here. 'result' w
Alexander Alekseev 2014/06/02 18:46:03 On 2014/06/02 15:30:31, stevenjb wrote: > nit: Sho
156
157 return result;
158 }
125 159
126 // static 160 // static
127 BootTimesLoader* BootTimesLoader::Get() { 161 BootTimesLoader::Stats BootTimesLoader::Stats::DeserializeFromString(
128 return g_boot_times_loader.Pointer(); 162 const std::string& source) {
163 if (source.empty())
164 return Stats();
165
166 scoped_ptr<base::Value> value(base::JSONReader::Read(source));
167 base::DictionaryValue* dictionary;
168 if (!value || !value->GetAsDictionary(&dictionary))
stevenjb 2014/06/02 15:30:31 LOG(ERROR)
Alexander Alekseev 2014/06/02 18:46:03 Done.
169 return Stats();
170
171 Stats result;
172 if (!dictionary->GetString(kUptime, &result.uptime_) ||
173 !dictionary->GetString(kDisk, &result.disk_)) {
stevenjb 2014/06/02 15:30:31 LOG(ERROR)
Alexander Alekseev 2014/06/02 18:46:03 Done.
174 return Stats();
175 }
176
177 return result;
129 } 178 }
130 179
131 // Appends the given buffer into the file. Returns the number of bytes 180 bool BootTimesLoader::Stats::uptimeD(double* result) const {
132 // written, or -1 on error. 181 std::string uptime = uptime_;
133 // TODO(satorux): Move this to file_util. 182 const size_t space_at = uptime.find_first_of(' ');
134 static int AppendFile(const base::FilePath& file_path, 183 if (space_at == std::string::npos)
135 const char* data, 184 return false;
136 int size) { 185
137 FILE* file = base::OpenFile(file_path, "a"); 186 uptime.resize(space_at);
138 if (!file) { 187
139 return -1; 188 if (base::StringToDouble(uptime, result))
140 } 189 return true;
141 const int num_bytes_written = fwrite(data, 1, size, file); 190
142 base::CloseFile(file); 191 return false;
143 return num_bytes_written;
144 } 192 }
145 193
146 static void RecordStatsDelayed(const base::FilePath::StringType& name, 194 void BootTimesLoader::Stats::RecordStats(const std::string& name) const {
147 const std::string& uptime, 195 BrowserThread::PostBlockingPoolTask(
148 const std::string& disk) { 196 FROM_HERE,
197 base::Bind(&BootTimesLoader::Stats::RecordStatsImpl,
198 base::Owned(new Stats(*this)),
199 name));
200 }
201
202 void BootTimesLoader::Stats::RecordStatsWithCallback(
203 const std::string& name,
204 const base::Closure& callback) const {
205 BrowserThread::PostBlockingPoolTaskAndReply(
206 FROM_HERE,
207 base::Bind(&BootTimesLoader::Stats::RecordStatsImpl,
208 base::Owned(new Stats(*this)),
209 name),
210 callback);
211 }
212
213 void BootTimesLoader::Stats::RecordStatsImpl(
214 const base::FilePath::StringType& name) const {
215 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
216
149 const base::FilePath log_path(kLogPath); 217 const base::FilePath log_path(kLogPath);
150 const base::FilePath uptime_output = 218 const base::FilePath uptime_output =
151 log_path.Append(base::FilePath(kUptimePrefix + name)); 219 log_path.Append(base::FilePath(kUptimePrefix + name));
152 const base::FilePath disk_output = 220 const base::FilePath disk_output =
153 log_path.Append(base::FilePath(kDiskPrefix + name)); 221 log_path.Append(base::FilePath(kDiskPrefix + name));
154 222
155 // Append numbers to the files. 223 // Append numbers to the files.
156 AppendFile(uptime_output, uptime.data(), uptime.size()); 224 AppendFile(uptime_output, uptime_.data(), uptime_.size());
157 AppendFile(disk_output, disk.data(), disk.size()); 225 AppendFile(disk_output, disk_.data(), disk_.size());
226 }
227
228 BootTimesLoader::BootTimesLoader()
229 : backend_(new Backend()),
230 have_registered_(false),
231 login_done_(false),
232 restart_requested_(false) {
233 login_time_markers_.reserve(30);
234 logout_time_markers_.reserve(30);
235 }
236
237 BootTimesLoader::~BootTimesLoader() {
158 } 238 }
159 239
160 // static 240 // static
241 BootTimesLoader* BootTimesLoader::Get() {
242 return g_boot_times_loader.Pointer();
243 }
244
245 // static
161 void BootTimesLoader::WriteTimes( 246 void BootTimesLoader::WriteTimes(
162 const std::string base_name, 247 const std::string base_name,
163 const std::string uma_name, 248 const std::string uma_name,
164 const std::string uma_prefix, 249 const std::string uma_prefix,
165 std::vector<TimeMarker> login_times) { 250 std::vector<TimeMarker> login_times) {
166 const int kMinTimeMillis = 1; 251 const int kMinTimeMillis = 1;
167 const int kMaxTimeMillis = 30000; 252 const int kMaxTimeMillis = 30000;
168 const int kNumBuckets = 100; 253 const int kNumBuckets = 100;
169 const base::FilePath log_path(kLoginLogPath); 254 const base::FilePath log_path(kLoginLogPath);
170 255
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 // has already been terminated. 343 // has already been terminated.
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || 344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
260 !BrowserThread::IsMessageLoopValid(BrowserThread::UI)); 345 !BrowserThread::IsMessageLoopValid(BrowserThread::UI));
261 346
262 WriteTimes(kLogoutTimes, 347 WriteTimes(kLogoutTimes,
263 (restart_requested_ ? kUmaRestart : kUmaLogout), 348 (restart_requested_ ? kUmaRestart : kUmaLogout),
264 kUmaLogoutPrefix, 349 kUmaLogoutPrefix,
265 logout_time_markers_); 350 logout_time_markers_);
266 } 351 }
267 352
268 void BootTimesLoader::RecordStats(const std::string& name, const Stats& stats) { 353 // static
269 BrowserThread::PostTask( 354 void BootTimesLoader::ClearLogoutStartedLastPreference() {
270 BrowserThread::FILE, FROM_HERE, 355 PrefService* local_state = g_browser_process->local_state();
271 base::Bind(&RecordStatsDelayed, name, stats.uptime, stats.disk)); 356 local_state->ClearPref(prefs::kLogoutStartedLast);
272 } 357 }
273 358
274 BootTimesLoader::Stats BootTimesLoader::GetCurrentStats() { 359 void BootTimesLoader::OnChromeProcessStart() {
275 const base::FilePath kProcUptime(FPL("/proc/uptime")); 360 PrefService* local_state = g_browser_process->local_state();
276 const base::FilePath kDiskStat(FPL("/sys/block/sda/stat")); 361 const std::string logout_started_last_str =
277 Stats stats; 362 local_state->GetString(prefs::kLogoutStartedLast);
278 base::ThreadRestrictions::ScopedAllowIO allow_io; 363 if (logout_started_last_str.empty())
279 base::ReadFileToString(kProcUptime, &stats.uptime); 364 return;
280 base::ReadFileToString(kDiskStat, &stats.disk); 365
281 return stats; 366 // Note that kLogoutStartedLast is not cleared on format error to stay in
367 // logs in case of other fatal system errors.
368
369 const Stats logout_started_last_stats =
370 Stats::DeserializeFromString(logout_started_last_str);
371 if (logout_started_last_stats.uptime().empty())
372 return;
373
374 double logout_started_last;
375 double uptime;
376 if (!logout_started_last_stats.uptimeD(&logout_started_last) ||
377 !Stats::GetCurrentStats().uptimeD(&uptime)) {
378 return;
379 }
380
381 if (logout_started_last >= uptime) {
382 // Reboot happened.
383 ClearLogoutStartedLastPreference();
384 return;
385 }
386
387 // Write /tmp/uptime-logout-started as well.
388 const char kLogoutStarted[] = "logout-started";
389 logout_started_last_stats.RecordStatsWithCallback(
390 kLogoutStarted,
391 base::Bind(&BootTimesLoader::ClearLogoutStartedLastPreference));
392 }
393
394 void BootTimesLoader::OnLogoutStarted(PrefService* state) {
395 const std::string uptime = Stats::GetCurrentStats().SerializeToString();
396 if (!uptime.empty())
397 state->SetString(prefs::kLogoutStartedLast, uptime);
282 } 398 }
283 399
284 void BootTimesLoader::RecordCurrentStats(const std::string& name) { 400 void BootTimesLoader::RecordCurrentStats(const std::string& name) {
285 RecordStats(name, GetCurrentStats()); 401 Stats::GetCurrentStats().RecordStats(name);
286 } 402 }
287 403
288 void BootTimesLoader::SaveChromeMainStats() { 404 void BootTimesLoader::SaveChromeMainStats() {
289 chrome_main_stats_ = GetCurrentStats(); 405 chrome_main_stats_ = Stats::GetCurrentStats();
290 } 406 }
291 407
292 void BootTimesLoader::RecordChromeMainStats() { 408 void BootTimesLoader::RecordChromeMainStats() {
293 RecordStats(kChromeMain, chrome_main_stats_); 409 chrome_main_stats_.RecordStats(kChromeMain);
294 } 410 }
295 411
296 void BootTimesLoader::RecordLoginAttempted() { 412 void BootTimesLoader::RecordLoginAttempted() {
297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
298 if (login_done_) 414 if (login_done_)
299 return; 415 return;
300 416
301 login_time_markers_.clear(); 417 login_time_markers_.clear();
302 AddLoginTimeMarker("LoginStarted", false); 418 AddLoginTimeMarker("LoginStarted", false);
303 if (!have_registered_) { 419 if (!have_registered_) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 GetRenderWidgetHost(&web_contents->GetController()); 514 GetRenderWidgetHost(&web_contents->GetController());
399 render_widget_hosts_loading_.erase(render_widget_host); 515 render_widget_hosts_loading_.erase(render_widget_host);
400 break; 516 break;
401 } 517 }
402 default: 518 default:
403 break; 519 break;
404 } 520 }
405 } 521 }
406 522
407 } // namespace chromeos 523 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698