session_restore.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/sessions/session_restore.h" 6 7#include <algorithm> 8#include <list> 9#include <set> 10#include <vector> 11 12#include "base/callback.h" 13#include "base/command_line.h" 14#include "base/scoped_ptr.h" 15#include "base/stl_util-inl.h" 16#include "base/string_util.h" 17#include "chrome/browser/extensions/extension_service.h" 18#include "chrome/browser/profiles/profile.h" 19#include "chrome/browser/sessions/session_service.h" 20#include "chrome/browser/sessions/session_types.h" 21#include "chrome/browser/tab_contents/navigation_controller.h" 22#include "chrome/browser/tab_contents/tab_contents.h" 23#include "chrome/browser/tab_contents/tab_contents_view.h" 24#include "chrome/browser/tabs/tab_strip_model.h" 25#include "chrome/browser/ui/browser.h" 26#include "chrome/browser/ui/browser_list.h" 27#include "chrome/browser/ui/browser_navigator.h" 28#include "chrome/browser/ui/browser_window.h" 29#include "chrome/common/chrome_switches.h" 30#include "chrome/common/notification_registrar.h" 31#include "chrome/common/notification_service.h" 32 33#if defined(OS_CHROMEOS) 34#include "chrome/browser/chromeos/boot_times_loader.h" 35#include "chrome/browser/chromeos/network_state_notifier.h" 36#endif 37 38// Are we in the process of restoring? 39static bool restoring = false; 40 41namespace { 42 43// TabLoader ------------------------------------------------------------------ 44 45// Initial delay (see class decription for details). 46static const int kInitialDelayTimerMS = 100; 47 48// TabLoader is responsible for loading tabs after session restore creates 49// tabs. New tabs are loaded after the current tab finishes loading, or a delay 50// is reached (initially kInitialDelayTimerMS). If the delay is reached before 51// a tab finishes loading a new tab is loaded and the time of the delay 52// doubled. When all tabs are loading TabLoader deletes itself. 53// 54// This is not part of SessionRestoreImpl so that synchronous destruction 55// of SessionRestoreImpl doesn't have timing problems. 56class TabLoader : public NotificationObserver { 57 public: 58 typedef std::list<NavigationController*> TabsToLoad; 59 60 TabLoader(); 61 ~TabLoader(); 62 63 // Schedules a tab for loading. 64 void ScheduleLoad(NavigationController* controller); 65 66 // Invokes |LoadNextTab| to load a tab. 67 // 68 // This must be invoked once to start loading. 69 void StartLoading(); 70 71 private: 72 typedef std::set<NavigationController*> TabsLoading; 73 74 // Loads the next tab. If there are no more tabs to load this deletes itself, 75 // otherwise |force_load_timer_| is restarted. 76 void LoadNextTab(); 77 78 // NotificationObserver method. Removes the specified tab and loads the next 79 // tab. 80 virtual void Observe(NotificationType type, 81 const NotificationSource& source, 82 const NotificationDetails& details); 83 84 // Removes the listeners from the specified tab and removes the tab from 85 // the set of tabs to load and list of tabs we're waiting to get a load 86 // from. 87 void RemoveTab(NavigationController* tab); 88 89 // Invoked from |force_load_timer_|. Doubles |force_load_delay_| and invokes 90 // |LoadNextTab| to load the next tab 91 void ForceLoadTimerFired(); 92 93 NotificationRegistrar registrar_; 94 95 // Current delay before a new tab is loaded. See class description for 96 // details. 97 int64 force_load_delay_; 98 99 // Has Load been invoked? 100 bool loading_; 101 102 // The set of tabs we've initiated loading on. This does NOT include the 103 // selected tabs. 104 TabsLoading tabs_loading_; 105 106 // The tabs we need to load. 107 TabsToLoad tabs_to_load_; 108 109 base::OneShotTimer<TabLoader> force_load_timer_; 110 111 DISALLOW_COPY_AND_ASSIGN(TabLoader); 112}; 113 114TabLoader::TabLoader() 115 : force_load_delay_(kInitialDelayTimerMS), 116 loading_(false) { 117} 118 119TabLoader::~TabLoader() { 120 DCHECK(tabs_to_load_.empty() && tabs_loading_.empty()); 121} 122 123void TabLoader::ScheduleLoad(NavigationController* controller) { 124 if (controller) { 125 DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) == 126 tabs_to_load_.end()); 127 tabs_to_load_.push_back(controller); 128 registrar_.Add(this, NotificationType::TAB_CLOSED, 129 Source<NavigationController>(controller)); 130 registrar_.Add(this, NotificationType::LOAD_STOP, 131 Source<NavigationController>(controller)); 132 } else { 133 // Should never get a NULL tab. 134 NOTREACHED(); 135 } 136} 137 138void TabLoader::StartLoading() { 139#if defined(OS_CHROMEOS) 140 if (chromeos::NetworkStateNotifier::is_connected()) { 141 loading_ = true; 142 LoadNextTab(); 143 } else { 144 // Start listening to network state notification now. 145 registrar_.Add(this, NotificationType::NETWORK_STATE_CHANGED, 146 NotificationService::AllSources()); 147 } 148#else 149 loading_ = true; 150 LoadNextTab(); 151#endif 152} 153 154void TabLoader::LoadNextTab() { 155 if (!tabs_to_load_.empty()) { 156 NavigationController* tab = tabs_to_load_.front(); 157 DCHECK(tab); 158 tabs_loading_.insert(tab); 159 tabs_to_load_.pop_front(); 160 tab->LoadIfNecessary(); 161 if (tab->tab_contents()) { 162 int tab_index; 163 Browser* browser = Browser::GetBrowserForController(tab, &tab_index); 164 if (browser && browser->selected_index() != tab_index) { 165 // By default tabs are marked as visible. As only the selected tab is 166 // visible we need to explicitly tell non-selected tabs they are hidden. 167 // Without this call non-selected tabs are not marked as backgrounded. 168 // 169 // NOTE: We need to do this here rather than when the tab is added to 170 // the Browser as at that time not everything has been created, so that 171 // the call would do nothing. 172 tab->tab_contents()->WasHidden(); 173 } 174 } 175 } 176 177 if (tabs_to_load_.empty()) { 178 tabs_loading_.clear(); 179 delete this; 180 return; 181 } 182 183 if (force_load_timer_.IsRunning()) 184 force_load_timer_.Stop(); 185 force_load_timer_.Start( 186 base::TimeDelta::FromMilliseconds(force_load_delay_), 187 this, &TabLoader::ForceLoadTimerFired); 188} 189 190void TabLoader::Observe(NotificationType type, 191 const NotificationSource& source, 192 const NotificationDetails& details) { 193 switch (type.value) { 194#if defined(OS_CHROMEOS) 195 case NotificationType::NETWORK_STATE_CHANGED: { 196 chromeos::NetworkStateDetails* state_details = 197 Details<chromeos::NetworkStateDetails>(details).ptr(); 198 switch (state_details->state()) { 199 case chromeos::NetworkStateDetails::CONNECTED: 200 if (!loading_) { 201 loading_ = true; 202 LoadNextTab(); 203 } 204 // Start loading 205 break; 206 case chromeos::NetworkStateDetails::CONNECTING: 207 case chromeos::NetworkStateDetails::DISCONNECTED: 208 // Disconnected while loading. Set loading_ false so 209 // that it stops trying to load next tab. 210 loading_ = false; 211 break; 212 default: 213 NOTREACHED() << "Unknown nework state notification:" 214 << state_details->state(); 215 } 216 break; 217 } 218#endif 219 case NotificationType::TAB_CLOSED: 220 case NotificationType::LOAD_STOP: { 221 NavigationController* tab = Source<NavigationController>(source).ptr(); 222 RemoveTab(tab); 223 if (loading_) { 224 LoadNextTab(); 225 // WARNING: if there are no more tabs to load, we have been deleted. 226 } else if (tabs_to_load_.empty()) { 227 tabs_loading_.clear(); 228 delete this; 229 return; 230 } 231 break; 232 } 233 default: 234 NOTREACHED() << "Unknown notification received:" << type.value; 235 } 236} 237 238void TabLoader::RemoveTab(NavigationController* tab) { 239 registrar_.Remove(this, NotificationType::TAB_CLOSED, 240 Source<NavigationController>(tab)); 241 registrar_.Remove(this, NotificationType::LOAD_STOP, 242 Source<NavigationController>(tab)); 243 244 TabsLoading::iterator i = tabs_loading_.find(tab); 245 if (i != tabs_loading_.end()) 246 tabs_loading_.erase(i); 247 248 TabsToLoad::iterator j = 249 find(tabs_to_load_.begin(), tabs_to_load_.end(), tab); 250 if (j != tabs_to_load_.end()) 251 tabs_to_load_.erase(j); 252} 253 254void TabLoader::ForceLoadTimerFired() { 255 force_load_delay_ *= 2; 256 LoadNextTab(); 257} 258 259// SessionRestoreImpl --------------------------------------------------------- 260 261// SessionRestoreImpl is responsible for fetching the set of tabs to create 262// from SessionService. SessionRestoreImpl deletes itself when done. 263 264class SessionRestoreImpl : public NotificationObserver { 265 public: 266 SessionRestoreImpl(Profile* profile, 267 Browser* browser, 268 bool synchronous, 269 bool clobber_existing_window, 270 bool always_create_tabbed_browser, 271 const std::vector<GURL>& urls_to_open) 272 : profile_(profile), 273 browser_(browser), 274 synchronous_(synchronous), 275 clobber_existing_window_(clobber_existing_window), 276 always_create_tabbed_browser_(always_create_tabbed_browser), 277 urls_to_open_(urls_to_open) { 278 } 279 280 void Restore() { 281 SessionService* session_service = profile_->GetSessionService(); 282 DCHECK(session_service); 283 SessionService::SessionCallback* callback = 284 NewCallback(this, &SessionRestoreImpl::OnGotSession); 285 session_service->GetLastSession(&request_consumer_, callback); 286 287 if (synchronous_) { 288 bool old_state = MessageLoop::current()->NestableTasksAllowed(); 289 MessageLoop::current()->SetNestableTasksAllowed(true); 290 MessageLoop::current()->Run(); 291 MessageLoop::current()->SetNestableTasksAllowed(old_state); 292 ProcessSessionWindows(&windows_); 293 delete this; 294 return; 295 } 296 297 if (browser_) { 298 registrar_.Add(this, NotificationType::BROWSER_CLOSED, 299 Source<Browser>(browser_)); 300 } 301 } 302 303 void RestoreForeignSession(std::vector<SessionWindow*>* windows) { 304 tab_loader_.reset(new TabLoader()); 305 // Create a browser instance to put the restored tabs in. 306 bool has_tabbed_browser = false; 307 for (std::vector<SessionWindow*>::iterator i = (*windows).begin(); 308 i != (*windows).end(); ++i) { 309 Browser* browser = NULL; 310 if (!has_tabbed_browser && (*i)->type == Browser::TYPE_NORMAL) 311 has_tabbed_browser = true; 312 browser = new Browser(static_cast<Browser::Type>((*i)->type), 313 profile_); 314 browser->set_override_bounds((*i)->bounds); 315 browser->set_maximized_state((*i)->is_maximized ? 316 Browser::MAXIMIZED_STATE_MAXIMIZED : 317 Browser::MAXIMIZED_STATE_UNMAXIMIZED); 318 browser->CreateBrowserWindow(); 319 320 // Restore and show the browser. 321 const int initial_tab_count = browser->tab_count(); 322 RestoreTabsToBrowser(*(*i), browser); 323 ShowBrowser(browser, initial_tab_count, 324 (*i)->selected_tab_index); 325 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count); 326 } 327 FinishedTabCreation(true, has_tabbed_browser); 328 } 329 330 ~SessionRestoreImpl() { 331 STLDeleteElements(&windows_); 332 restoring = false; 333 } 334 335 virtual void Observe(NotificationType type, 336 const NotificationSource& source, 337 const NotificationDetails& details) { 338 switch (type.value) { 339 case NotificationType::BROWSER_CLOSED: 340 delete this; 341 return; 342 343 default: 344 NOTREACHED(); 345 break; 346 } 347 } 348 349 private: 350 // Invoked when done with creating all the tabs/browsers. 351 // 352 // |created_tabbed_browser| indicates whether a tabbed browser was created, 353 // or we used an existing tabbed browser. 354 // 355 // If successful, this begins loading tabs and deletes itself when all tabs 356 // have been loaded. 357 void FinishedTabCreation(bool succeeded, bool created_tabbed_browser) { 358 if (!created_tabbed_browser && always_create_tabbed_browser_) { 359 Browser* browser = Browser::Create(profile_); 360 if (urls_to_open_.empty()) { 361 // No tab browsers were created and no URLs were supplied on the command 362 // line. Add an empty URL, which is treated as opening the users home 363 // page. 364 urls_to_open_.push_back(GURL()); 365 } 366 AppendURLsToBrowser(browser, urls_to_open_); 367 browser->window()->Show(); 368 } 369 370 if (succeeded) { 371 DCHECK(tab_loader_.get()); 372 // TabLoader delets itself when done loading. 373 tab_loader_.release()->StartLoading(); 374 } 375 376 if (!synchronous_) { 377 // If we're not synchronous we need to delete ourself. 378 // NOTE: we must use DeleteLater here as most likely we're in a callback 379 // from the history service which doesn't deal well with deleting the 380 // object it is notifying. 381 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 382 } 383 } 384 385 void OnGotSession(SessionService::Handle handle, 386 std::vector<SessionWindow*>* windows) { 387 if (synchronous_) { 388 // See comment above windows_ as to why we don't process immediately. 389 windows_.swap(*windows); 390 MessageLoop::current()->Quit(); 391 return; 392 } 393 394 ProcessSessionWindows(windows); 395 } 396 397 void ProcessSessionWindows(std::vector<SessionWindow*>* windows) { 398 if (windows->empty()) { 399 // Restore was unsuccessful. 400 FinishedTabCreation(false, false); 401 return; 402 } 403 404 tab_loader_.reset(new TabLoader()); 405 406 Browser* current_browser = 407 browser_ ? browser_ : BrowserList::GetLastActive(); 408 // After the for loop this contains the last TABBED_BROWSER. Is null if no 409 // tabbed browsers exist. 410 Browser* last_browser = NULL; 411 bool has_tabbed_browser = false; 412 for (std::vector<SessionWindow*>::iterator i = windows->begin(); 413 i != windows->end(); ++i) { 414 Browser* browser = NULL; 415 if (!has_tabbed_browser && (*i)->type == Browser::TYPE_NORMAL) 416 has_tabbed_browser = true; 417 if (i == windows->begin() && (*i)->type == Browser::TYPE_NORMAL && 418 !clobber_existing_window_) { 419 // If there is an open tabbed browser window, use it. Otherwise fall 420 // through and create a new one. 421 browser = current_browser; 422 if (browser && (browser->type() != Browser::TYPE_NORMAL || 423 browser->profile()->IsOffTheRecord())) { 424 browser = NULL; 425 } 426 } 427 if (!browser) { 428 browser = new Browser(static_cast<Browser::Type>((*i)->type), profile_); 429 browser->set_override_bounds((*i)->bounds); 430 browser->set_maximized_state((*i)->is_maximized ? 431 Browser::MAXIMIZED_STATE_MAXIMIZED : 432 Browser::MAXIMIZED_STATE_UNMAXIMIZED); 433 browser->CreateBrowserWindow(); 434 } 435 if ((*i)->type == Browser::TYPE_NORMAL) 436 last_browser = browser; 437 const int initial_tab_count = browser->tab_count(); 438 RestoreTabsToBrowser(*(*i), browser); 439 ShowBrowser(browser, initial_tab_count, (*i)->selected_tab_index); 440 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count); 441 } 442 443 // If we're restoring a session as the result of a crash and the session 444 // included at least one tabbed browser, then close the browser window 445 // that was opened when the user clicked to restore the session. 446 if (clobber_existing_window_ && current_browser && has_tabbed_browser && 447 current_browser->type() == Browser::TYPE_NORMAL) { 448 current_browser->CloseAllTabs(); 449 } 450 if (last_browser && !urls_to_open_.empty()) 451 AppendURLsToBrowser(last_browser, urls_to_open_); 452 // If last_browser is NULL and urls_to_open_ is non-empty, 453 // FinishedTabCreation will create a new TabbedBrowser and add the urls to 454 // it. 455 FinishedTabCreation(true, has_tabbed_browser); 456 } 457 458 void RestoreTabsToBrowser(const SessionWindow& window, Browser* browser) { 459 DCHECK(!window.tabs.empty()); 460 for (std::vector<SessionTab*>::const_iterator i = window.tabs.begin(); 461 i != window.tabs.end(); ++i) { 462 const SessionTab& tab = *(*i); 463 DCHECK(!tab.navigations.empty()); 464 int selected_index = tab.current_navigation_index; 465 selected_index = std::max( 466 0, 467 std::min(selected_index, 468 static_cast<int>(tab.navigations.size() - 1))); 469 tab_loader_->ScheduleLoad( 470 &browser->AddRestoredTab(tab.navigations, 471 static_cast<int>(i - window.tabs.begin()), 472 selected_index, 473 tab.extension_app_id, 474 false, 475 tab.pinned, 476 true, 477 NULL)->controller()); 478 } 479 } 480 481 void ShowBrowser(Browser* browser, 482 int initial_tab_count, 483 int selected_session_index) { 484 if (browser_ == browser) { 485 browser->SelectTabContentsAt(browser->tab_count() - 1, true); 486 return; 487 } 488 489 DCHECK(browser); 490 DCHECK(browser->tab_count()); 491 browser->SelectTabContentsAt( 492 std::min(initial_tab_count + std::max(0, selected_session_index), 493 browser->tab_count() - 1), true); 494 browser->window()->Show(); 495 // TODO(jcampan): http://crbug.com/8123 we should not need to set the 496 // initial focus explicitly. 497 browser->GetSelectedTabContents()->view()->SetInitialFocus(); 498 } 499 500 // Appends the urls in |urls| to |browser|. 501 void AppendURLsToBrowser(Browser* browser, 502 const std::vector<GURL>& urls) { 503 for (size_t i = 0; i < urls.size(); ++i) { 504 int add_types = TabStripModel::ADD_FORCE_INDEX; 505 if (i == 0) 506 add_types |= TabStripModel::ADD_SELECTED; 507 int index = browser->GetIndexForInsertionDuringRestore(i); 508 browser::NavigateParams params(browser, urls[i], 509 PageTransition::START_PAGE); 510 params.disposition = i == 0 ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB; 511 params.tabstrip_index = index; 512 params.tabstrip_add_types = add_types; 513 browser::Navigate(¶ms); 514 } 515 } 516 517 // Invokes TabRestored on the SessionService for all tabs in browser after 518 // initial_count. 519 void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) { 520 SessionService* session_service = profile_->GetSessionService(); 521 for (int i = initial_count; i < browser->tab_count(); ++i) 522 session_service->TabRestored(&browser->GetTabContentsAt(i)->controller(), 523 browser->tabstrip_model()->IsTabPinned(i)); 524 } 525 526 // The profile to create the sessions for. 527 Profile* profile_; 528 529 // The first browser to restore to, may be null. 530 Browser* browser_; 531 532 // Whether or not restore is synchronous. 533 const bool synchronous_; 534 535 // See description in RestoreSession (in .h). 536 const bool clobber_existing_window_; 537 538 // If true and there is an error or there are no windows to restore, we 539 // create a tabbed browser anyway. This is used on startup to make sure at 540 // at least one window is created. 541 const bool always_create_tabbed_browser_; 542 543 // Set of URLs to open in addition to those restored from the session. 544 std::vector<GURL> urls_to_open_; 545 546 // Used to get the session. 547 CancelableRequestConsumer request_consumer_; 548 549 // Responsible for loading the tabs. 550 scoped_ptr<TabLoader> tab_loader_; 551 552 // When synchronous we run a nested message loop. To avoid creating windows 553 // from the nested message loop (which can make exiting the nested message 554 // loop take a while) we cache the SessionWindows here and create the actual 555 // windows when the nested message loop exits. 556 std::vector<SessionWindow*> windows_; 557 558 NotificationRegistrar registrar_; 559}; 560 561} // namespace 562 563// SessionRestore ------------------------------------------------------------- 564 565static void Restore(Profile* profile, 566 Browser* browser, 567 bool synchronous, 568 bool clobber_existing_window, 569 bool always_create_tabbed_browser, 570 const std::vector<GURL>& urls_to_open) { 571#if defined(OS_CHROMEOS) 572 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 573 "SessionRestoreStarted", false); 574#endif 575 DCHECK(profile); 576 // Always restore from the original profile (incognito profiles have no 577 // session service). 578 profile = profile->GetOriginalProfile(); 579 if (!profile->GetSessionService()) { 580 NOTREACHED(); 581 return; 582 } 583 restoring = true; 584 profile->set_restored_last_session(true); 585 // SessionRestoreImpl takes care of deleting itself when done. 586 SessionRestoreImpl* restorer = 587 new SessionRestoreImpl(profile, browser, synchronous, 588 clobber_existing_window, 589 always_create_tabbed_browser, urls_to_open); 590 restorer->Restore(); 591} 592 593// static 594void SessionRestore::RestoreSession(Profile* profile, 595 Browser* browser, 596 bool clobber_existing_window, 597 bool always_create_tabbed_browser, 598 const std::vector<GURL>& urls_to_open) { 599 Restore(profile, browser, false, clobber_existing_window, 600 always_create_tabbed_browser, urls_to_open); 601} 602 603// static 604void SessionRestore::RestoreForeignSessionWindows(Profile* profile, 605 std::vector<SessionWindow*>* windows) { 606 // Create a SessionRestore object to eventually restore the tabs. 607 std::vector<GURL> gurls; 608 SessionRestoreImpl restorer(profile, 609 static_cast<Browser*>(NULL), true, false, true, gurls); 610 restorer.RestoreForeignSession(windows); 611} 612 613// static 614void SessionRestore::RestoreSessionSynchronously( 615 Profile* profile, 616 const std::vector<GURL>& urls_to_open) { 617 Restore(profile, NULL, true, false, true, urls_to_open); 618} 619 620// static 621bool SessionRestore::IsRestoring() { 622 return restoring; 623} 624