OLD | NEW |
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/login/update_screen.h" | 5 #include "chrome/browser/chromeos/login/update_screen.h" |
6 | 6 |
| 7 #include <algorithm> |
| 8 |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/file_util.h" | 10 #include "base/file_util.h" |
9 #include "base/logging.h" | 11 #include "base/logging.h" |
10 #include "base/threading/thread_restrictions.h" | 12 #include "base/threading/thread_restrictions.h" |
11 #include "chrome/browser/chromeos/login/screen_observer.h" | 13 #include "chrome/browser/chromeos/login/screen_observer.h" |
12 #include "chrome/browser/chromeos/login/update_screen_actor.h" | 14 #include "chrome/browser/chromeos/login/update_screen_actor.h" |
13 #include "chrome/browser/chromeos/login/wizard_controller.h" | 15 #include "chrome/browser/chromeos/login/wizard_controller.h" |
14 #include "chromeos/dbus/dbus_thread_manager.h" | 16 #include "chromeos/dbus/dbus_thread_manager.h" |
15 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
16 | 18 |
(...skipping 15 matching lines...) Expand all Loading... |
32 | 34 |
33 // Defines what part of update progress does download part takes. | 35 // Defines what part of update progress does download part takes. |
34 const int kDownloadProgressIncrement = 60; | 36 const int kDownloadProgressIncrement = 60; |
35 | 37 |
36 // Considering 10px shadow from each side. | 38 // Considering 10px shadow from each side. |
37 const int kUpdateScreenWidth = 580; | 39 const int kUpdateScreenWidth = 580; |
38 const int kUpdateScreenHeight = 305; | 40 const int kUpdateScreenHeight = 305; |
39 | 41 |
40 const char kUpdateDeadlineFile[] = "/tmp/update-check-response-deadline"; | 42 const char kUpdateDeadlineFile[] = "/tmp/update-check-response-deadline"; |
41 | 43 |
| 44 // Minimum timestep between two consecutive measurements for the |
| 45 // download rate. |
| 46 const base::TimeDelta kMinTimeStep = base::TimeDelta::FromSeconds(1); |
| 47 |
| 48 // Minimum allowed progress between two consecutive ETAs. |
| 49 const double kMinProgressStep = 1e-3; |
| 50 |
| 51 // Smooth factor that is used for the average downloading speed |
| 52 // estimation. |
| 53 const double kDownloadSpeedSmoothFactor = 0.005; |
| 54 |
| 55 // Minumum allowed value for the average downloading speed. |
| 56 const double kDownloadAverageSpeedDropBound = 1e-8; |
| 57 |
| 58 // An upper bound for possible downloading time left estimations. |
| 59 const double kMaxTimeLeft = 24 * 60 * 60; |
| 60 |
42 // Invoked from call to RequestUpdateCheck upon completion of the DBus call. | 61 // Invoked from call to RequestUpdateCheck upon completion of the DBus call. |
43 void StartUpdateCallback(UpdateScreen* screen, | 62 void StartUpdateCallback(UpdateScreen* screen, |
44 UpdateEngineClient::UpdateCheckResult result) { | 63 UpdateEngineClient::UpdateCheckResult result) { |
45 VLOG(1) << "Callback from RequestUpdateCheck, result " << result; | 64 VLOG(1) << "Callback from RequestUpdateCheck, result " << result; |
46 if (UpdateScreen::HasInstance(screen)) { | 65 if (UpdateScreen::HasInstance(screen)) { |
47 if (result == UpdateEngineClient::UPDATE_RESULT_SUCCESS) | 66 if (result == UpdateEngineClient::UPDATE_RESULT_SUCCESS) |
48 screen->SetIgnoreIdleStatus(false); | 67 screen->SetIgnoreIdleStatus(false); |
49 else | 68 else |
50 screen->ExitUpdate(UpdateScreen::REASON_UPDATE_INIT_FAILED); | 69 screen->ExitUpdate(UpdateScreen::REASON_UPDATE_INIT_FAILED); |
51 } | 70 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 } | 119 } |
101 | 120 |
102 switch (status.status) { | 121 switch (status.status) { |
103 case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE: | 122 case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE: |
104 // Do nothing in these cases, we don't want to notify the user of the | 123 // Do nothing in these cases, we don't want to notify the user of the |
105 // check unless there is an update. | 124 // check unless there is an update. |
106 break; | 125 break; |
107 case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE: | 126 case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE: |
108 MakeSureScreenIsShown(); | 127 MakeSureScreenIsShown(); |
109 actor_->SetProgress(kBeforeDownloadProgress); | 128 actor_->SetProgress(kBeforeDownloadProgress); |
| 129 actor_->ShowEstimatedTimeLeft(false); |
110 if (!HasCriticalUpdate()) { | 130 if (!HasCriticalUpdate()) { |
111 LOG(INFO) << "Noncritical update available: " | 131 LOG(INFO) << "Noncritical update available: " |
112 << status.new_version; | 132 << status.new_version; |
113 ExitUpdate(REASON_UPDATE_NON_CRITICAL); | 133 ExitUpdate(REASON_UPDATE_NON_CRITICAL); |
114 } else { | 134 } else { |
115 LOG(INFO) << "Critical update available: " | 135 LOG(INFO) << "Critical update available: " |
116 << status.new_version; | 136 << status.new_version; |
117 actor_->ShowPreparingUpdatesInfo(true); | 137 actor_->ShowPreparingUpdatesInfo(true); |
118 actor_->ShowCurtain(false); | 138 actor_->ShowCurtain(false); |
119 } | 139 } |
120 break; | 140 break; |
121 case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING: | 141 case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING: |
122 { | 142 { |
123 MakeSureScreenIsShown(); | 143 MakeSureScreenIsShown(); |
124 if (!is_downloading_update_) { | 144 if (!is_downloading_update_) { |
125 // Because update engine doesn't send UPDATE_STATUS_UPDATE_AVAILABLE | 145 // Because update engine doesn't send UPDATE_STATUS_UPDATE_AVAILABLE |
126 // we need to is update critical on first downloading notification. | 146 // we need to is update critical on first downloading notification. |
127 is_downloading_update_ = true; | 147 is_downloading_update_ = true; |
| 148 download_start_time_ = download_last_time_ = base::Time::Now(); |
| 149 download_start_progress_ = status.download_progress; |
| 150 download_last_progress_ = status.download_progress; |
| 151 is_download_average_speed_computed_ = false; |
| 152 download_average_speed_ = 0.0; |
128 if (!HasCriticalUpdate()) { | 153 if (!HasCriticalUpdate()) { |
129 LOG(INFO) << "Non-critical update available: " | 154 LOG(INFO) << "Non-critical update available: " |
130 << status.new_version; | 155 << status.new_version; |
131 ExitUpdate(REASON_UPDATE_NON_CRITICAL); | 156 ExitUpdate(REASON_UPDATE_NON_CRITICAL); |
132 } else { | 157 } else { |
133 LOG(INFO) << "Critical update available: " | 158 LOG(INFO) << "Critical update available: " |
134 << status.new_version; | 159 << status.new_version; |
135 actor_->ShowPreparingUpdatesInfo(false); | 160 actor_->ShowPreparingUpdatesInfo(false); |
136 actor_->ShowCurtain(false); | 161 actor_->ShowCurtain(false); |
137 } | 162 } |
138 } | 163 } |
139 int download_progress = static_cast<int>( | 164 UpdateDownloadingStats(status); |
140 status.download_progress * kDownloadProgressIncrement); | |
141 actor_->SetProgress(kBeforeDownloadProgress + download_progress); | |
142 } | 165 } |
143 break; | 166 break; |
144 case UpdateEngineClient::UPDATE_STATUS_VERIFYING: | 167 case UpdateEngineClient::UPDATE_STATUS_VERIFYING: |
145 MakeSureScreenIsShown(); | 168 MakeSureScreenIsShown(); |
146 actor_->SetProgress(kBeforeVerifyingProgress); | 169 actor_->SetProgress(kBeforeVerifyingProgress); |
| 170 actor_->ShowEstimatedTimeLeft(false); |
147 break; | 171 break; |
148 case UpdateEngineClient::UPDATE_STATUS_FINALIZING: | 172 case UpdateEngineClient::UPDATE_STATUS_FINALIZING: |
149 MakeSureScreenIsShown(); | 173 MakeSureScreenIsShown(); |
150 actor_->SetProgress(kBeforeFinalizingProgress); | 174 actor_->SetProgress(kBeforeFinalizingProgress); |
| 175 actor_->ShowEstimatedTimeLeft(false); |
151 break; | 176 break; |
152 case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT: | 177 case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT: |
153 MakeSureScreenIsShown(); | 178 MakeSureScreenIsShown(); |
154 // Make sure that first OOBE stage won't be shown after reboot. | 179 // Make sure that first OOBE stage won't be shown after reboot. |
155 WizardController::MarkOobeCompleted(); | 180 WizardController::MarkOobeCompleted(); |
156 actor_->SetProgress(kProgressComplete); | 181 actor_->SetProgress(kProgressComplete); |
| 182 actor_->ShowEstimatedTimeLeft(false); |
157 if (HasCriticalUpdate()) { | 183 if (HasCriticalUpdate()) { |
158 actor_->ShowCurtain(false); | 184 actor_->ShowCurtain(false); |
159 VLOG(1) << "Initiate reboot after update"; | 185 VLOG(1) << "Initiate reboot after update"; |
160 DBusThreadManager::Get()->GetUpdateEngineClient()->RebootAfterUpdate(); | 186 DBusThreadManager::Get()->GetUpdateEngineClient()->RebootAfterUpdate(); |
161 reboot_timer_.Start(FROM_HERE, | 187 reboot_timer_.Start(FROM_HERE, |
162 base::TimeDelta::FromSeconds(reboot_check_delay_), | 188 base::TimeDelta::FromSeconds(reboot_check_delay_), |
163 this, | 189 this, |
164 &UpdateScreen::OnWaitForRebootTimeElapsed); | 190 &UpdateScreen::OnWaitForRebootTimeElapsed); |
165 } else { | 191 } else { |
166 ExitUpdate(REASON_UPDATE_NON_CRITICAL); | 192 ExitUpdate(REASON_UPDATE_NON_CRITICAL); |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 if (seconds <= 0) | 295 if (seconds <= 0) |
270 reboot_timer_.Stop(); | 296 reboot_timer_.Stop(); |
271 DCHECK(!reboot_timer_.IsRunning()); | 297 DCHECK(!reboot_timer_.IsRunning()); |
272 reboot_check_delay_ = seconds; | 298 reboot_check_delay_ = seconds; |
273 } | 299 } |
274 | 300 |
275 void UpdateScreen::SetIgnoreIdleStatus(bool ignore_idle_status) { | 301 void UpdateScreen::SetIgnoreIdleStatus(bool ignore_idle_status) { |
276 ignore_idle_status_ = ignore_idle_status; | 302 ignore_idle_status_ = ignore_idle_status; |
277 } | 303 } |
278 | 304 |
| 305 void UpdateScreen::UpdateDownloadingStats( |
| 306 const UpdateEngineClient::Status& status) { |
| 307 base::Time download_current_time = base::Time::Now(); |
| 308 if (download_current_time >= download_last_time_ + kMinTimeStep && |
| 309 status.download_progress >= |
| 310 download_last_progress_ + kMinProgressStep) { |
| 311 // Estimate downloading rate. |
| 312 double progress_delta = |
| 313 std::max(status.download_progress - download_last_progress_, 0.0); |
| 314 double time_delta = |
| 315 (download_current_time - download_last_time_).InSecondsF(); |
| 316 double download_rate = status.new_size * progress_delta / time_delta; |
| 317 |
| 318 download_last_time_ = download_current_time; |
| 319 download_last_progress_ = status.download_progress; |
| 320 |
| 321 // Estimate time left. |
| 322 double progress_left = std::max(1.0 - status.download_progress, 0.0); |
| 323 if (!is_download_average_speed_computed_) { |
| 324 download_average_speed_ = download_rate; |
| 325 is_download_average_speed_computed_ = true; |
| 326 } |
| 327 download_average_speed_ = |
| 328 kDownloadSpeedSmoothFactor * download_rate + |
| 329 (1.0 - kDownloadSpeedSmoothFactor) * download_average_speed_; |
| 330 if (download_average_speed_ < kDownloadAverageSpeedDropBound) { |
| 331 time_delta = |
| 332 (download_current_time - download_start_time_).InSecondsF(); |
| 333 download_average_speed_ = |
| 334 status.new_size * |
| 335 (status.download_progress - download_start_progress_) / |
| 336 time_delta; |
| 337 } |
| 338 double work_left = progress_left * status.new_size; |
| 339 double time_left = work_left / download_average_speed_; |
| 340 // |time_left| may be large enough or even +infinity. So we must |
| 341 // |bound possible estimations. |
| 342 time_left = std::min(time_left, kMaxTimeLeft); |
| 343 |
| 344 actor_->ShowEstimatedTimeLeft(true); |
| 345 actor_->SetEstimatedTimeLeft( |
| 346 base::TimeDelta::FromSeconds(static_cast<int64>(time_left))); |
| 347 } |
| 348 |
| 349 int download_progress = static_cast<int>( |
| 350 status.download_progress * kDownloadProgressIncrement); |
| 351 actor_->SetProgress(kBeforeDownloadProgress + download_progress); |
| 352 } |
| 353 |
279 bool UpdateScreen::HasCriticalUpdate() { | 354 bool UpdateScreen::HasCriticalUpdate() { |
280 if (is_ignore_update_deadlines_) | 355 if (is_ignore_update_deadlines_) |
281 return true; | 356 return true; |
282 | 357 |
283 std::string deadline; | 358 std::string deadline; |
284 // Checking for update flag file causes us to do blocking IO on UI thread. | 359 // Checking for update flag file causes us to do blocking IO on UI thread. |
285 // Temporarily allow it until we fix http://crosbug.com/11106 | 360 // Temporarily allow it until we fix http://crosbug.com/11106 |
286 base::ThreadRestrictions::ScopedAllowIO allow_io; | 361 base::ThreadRestrictions::ScopedAllowIO allow_io; |
287 FilePath update_deadline_file_path(kUpdateDeadlineFile); | 362 FilePath update_deadline_file_path(kUpdateDeadlineFile); |
288 if (!file_util::ReadFileToString(update_deadline_file_path, &deadline) || | 363 if (!file_util::ReadFileToString(update_deadline_file_path, &deadline) || |
289 deadline.empty()) { | 364 deadline.empty()) { |
290 return false; | 365 return false; |
291 } | 366 } |
292 | 367 |
293 // TODO(dpolukhin): Analyze file content. Now we can just assume that | 368 // TODO(dpolukhin): Analyze file content. Now we can just assume that |
294 // if the file exists and not empty, there is critical update. | 369 // if the file exists and not empty, there is critical update. |
295 return true; | 370 return true; |
296 } | 371 } |
297 | 372 |
298 void UpdateScreen::OnActorDestroyed(UpdateScreenActor* actor) { | 373 void UpdateScreen::OnActorDestroyed(UpdateScreenActor* actor) { |
299 if (actor_ == actor) | 374 if (actor_ == actor) |
300 actor_ = NULL; | 375 actor_ = NULL; |
301 } | 376 } |
302 | 377 |
303 } // namespace chromeos | 378 } // namespace chromeos |
OLD | NEW |