session_restore.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
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/metrics/histogram.h" 15#include "base/scoped_ptr.h" 16#include "base/stl_util-inl.h" 17#include "base/string_util.h" 18#include "chrome/browser/extensions/extension_service.h" 19#include "chrome/browser/profiles/profile.h" 20#include "chrome/browser/renderer_host/render_widget_host.h" 21#include "chrome/browser/renderer_host/render_widget_host_view.h" 22#include "chrome/browser/sessions/session_service.h" 23#include "chrome/browser/sessions/session_types.h" 24#include "chrome/browser/tab_contents/navigation_controller.h" 25#include "chrome/browser/tab_contents/tab_contents.h" 26#include "chrome/browser/tab_contents/tab_contents_view.h" 27#include "chrome/browser/tabs/tab_strip_model.h" 28#include "chrome/browser/ui/browser.h" 29#include "chrome/browser/ui/browser_list.h" 30#include "chrome/browser/ui/browser_navigator.h" 31#include "chrome/browser/ui/browser_window.h" 32#include "chrome/common/notification_registrar.h" 33#include "chrome/common/notification_service.h" 34 35#if defined(OS_CHROMEOS) 36#include "chrome/browser/chromeos/boot_times_loader.h" 37#include "chrome/browser/chromeos/network_state_notifier.h" 38#endif 39 40// Are we in the process of restoring? 41static bool restoring = false; 42 43namespace { 44 45// TabLoader ------------------------------------------------------------------ 46 47// Initial delay (see class decription for details). 48static const int kInitialDelayTimerMS = 100; 49 50// TabLoader is responsible for loading tabs after session restore creates 51// tabs. New tabs are loaded after the current tab finishes loading, or a delay 52// is reached (initially kInitialDelayTimerMS). If the delay is reached before 53// a tab finishes loading a new tab is loaded and the time of the delay 54// doubled. When all tabs are loading TabLoader deletes itself. 55// 56// This is not part of SessionRestoreImpl so that synchronous destruction 57// of SessionRestoreImpl doesn't have timing problems. 58class TabLoader : public NotificationObserver { 59 public: 60 explicit TabLoader(base::TimeTicks restore_started); 61 ~TabLoader(); 62 63 // Schedules a tab for loading. 64 void ScheduleLoad(NavigationController* controller); 65 66 // Notifies the loader that a tab has been scheduled for loading through 67 // some other mechanism. 68 void TabIsLoading(NavigationController* controller); 69 70 // Invokes |LoadNextTab| to load a tab. 71 // 72 // This must be invoked once to start loading. 73 void StartLoading(); 74 75 private: 76 typedef std::set<NavigationController*> TabsLoading; 77 typedef std::list<NavigationController*> TabsToLoad; 78 typedef std::set<RenderWidgetHost*> RenderWidgetHostSet; 79 80 // Loads the next tab. If there are no more tabs to load this deletes itself, 81 // otherwise |force_load_timer_| is restarted. 82 void LoadNextTab(); 83 84 // NotificationObserver method. Removes the specified tab and loads the next 85 // tab. 86 virtual void Observe(NotificationType type, 87 const NotificationSource& source, 88 const NotificationDetails& details); 89 90 // Removes the listeners from the specified tab and removes the tab from 91 // the set of tabs to load and list of tabs we're waiting to get a load 92 // from. 93 void RemoveTab(NavigationController* tab); 94 95 // Invoked from |force_load_timer_|. Doubles |force_load_delay_| and invokes 96 // |LoadNextTab| to load the next tab 97 void ForceLoadTimerFired(); 98 99 // Returns the RenderWidgetHost associated with a tab if there is one, 100 // NULL otherwise. 101 static RenderWidgetHost* GetRenderWidgetHost(NavigationController* tab); 102 103 // Register for necessary notificaitons on a tab navigation controller. 104 void RegisterForNotifications(NavigationController* controller); 105 106 // Called when a tab goes away or a load completes. 107 void HandleTabClosedOrLoaded(NavigationController* controller); 108 109 NotificationRegistrar registrar_; 110 111 // Current delay before a new tab is loaded. See class description for 112 // details. 113 int64 force_load_delay_; 114 115 // Has Load been invoked? 116 bool loading_; 117 118 // Have we recorded the times for a tab paint? 119 bool got_first_paint_; 120 121 // The set of tabs we've initiated loading on. This does NOT include the 122 // selected tabs. 123 TabsLoading tabs_loading_; 124 125 // The tabs we need to load. 126 TabsToLoad tabs_to_load_; 127 128 // The renderers we have started loading into. 129 RenderWidgetHostSet render_widget_hosts_loading_; 130 131 // The renderers we have loaded and are waiting on to paint. 132 RenderWidgetHostSet render_widget_hosts_to_paint_; 133 134 // The number of tabs that have been restored. 135 int tab_count_; 136 137 base::OneShotTimer<TabLoader> force_load_timer_; 138 139 // The time the restore process started. 140 base::TimeTicks restore_started_; 141 142 DISALLOW_COPY_AND_ASSIGN(TabLoader); 143}; 144 145TabLoader::TabLoader(base::TimeTicks restore_started) 146 : force_load_delay_(kInitialDelayTimerMS), 147 loading_(false), 148 got_first_paint_(false), 149 tab_count_(0), 150 restore_started_(restore_started) { 151} 152 153TabLoader::~TabLoader() { 154 DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && 155 tabs_loading_.empty() && tabs_to_load_.empty()); 156} 157 158void TabLoader::ScheduleLoad(NavigationController* controller) { 159 DCHECK(controller); 160 DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) == 161 tabs_to_load_.end()); 162 tabs_to_load_.push_back(controller); 163 RegisterForNotifications(controller); 164} 165 166void TabLoader::TabIsLoading(NavigationController* controller) { 167 DCHECK(controller); 168 DCHECK(find(tabs_loading_.begin(), tabs_loading_.end(), controller) == 169 tabs_loading_.end()); 170 tabs_loading_.insert(controller); 171 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(controller); 172 DCHECK(render_widget_host); 173 render_widget_hosts_loading_.insert(render_widget_host); 174 RegisterForNotifications(controller); 175} 176 177void TabLoader::StartLoading() { 178 registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DID_PAINT, 179 NotificationService::AllSources()); 180#if defined(OS_CHROMEOS) 181 if (chromeos::NetworkStateNotifier::is_connected()) { 182 loading_ = true; 183 LoadNextTab(); 184 } else { 185 // Start listening to network state notification now. 186 registrar_.Add(this, NotificationType::NETWORK_STATE_CHANGED, 187 NotificationService::AllSources()); 188 } 189#else 190 loading_ = true; 191 LoadNextTab(); 192#endif 193} 194 195void TabLoader::LoadNextTab() { 196 if (!tabs_to_load_.empty()) { 197 NavigationController* tab = tabs_to_load_.front(); 198 DCHECK(tab); 199 tabs_loading_.insert(tab); 200 tabs_to_load_.pop_front(); 201 tab->LoadIfNecessary(); 202 if (tab->tab_contents()) { 203 int tab_index; 204 Browser* browser = Browser::GetBrowserForController(tab, &tab_index); 205 if (browser && browser->selected_index() != tab_index) { 206 // By default tabs are marked as visible. As only the selected tab is 207 // visible we need to explicitly tell non-selected tabs they are hidden. 208 // Without this call non-selected tabs are not marked as backgrounded. 209 // 210 // NOTE: We need to do this here rather than when the tab is added to 211 // the Browser as at that time not everything has been created, so that 212 // the call would do nothing. 213 tab->tab_contents()->WasHidden(); 214 } 215 } 216 } 217 218 if (!tabs_to_load_.empty()) { 219 force_load_timer_.Stop(); 220 // Each time we load a tab we also set a timer to force us to start loading 221 // the next tab if this one doesn't load quickly enough. 222 force_load_timer_.Start( 223 base::TimeDelta::FromMilliseconds(force_load_delay_), 224 this, &TabLoader::ForceLoadTimerFired); 225 } 226} 227 228void TabLoader::Observe(NotificationType type, 229 const NotificationSource& source, 230 const NotificationDetails& details) { 231 switch (type.value) { 232#if defined(OS_CHROMEOS) 233 case NotificationType::NETWORK_STATE_CHANGED: { 234 chromeos::NetworkStateDetails* state_details = 235 Details<chromeos::NetworkStateDetails>(details).ptr(); 236 switch (state_details->state()) { 237 case chromeos::NetworkStateDetails::CONNECTED: 238 if (!loading_) { 239 loading_ = true; 240 LoadNextTab(); 241 } 242 // Start loading 243 break; 244 case chromeos::NetworkStateDetails::CONNECTING: 245 case chromeos::NetworkStateDetails::DISCONNECTED: 246 // Disconnected while loading. Set loading_ false so 247 // that it stops trying to load next tab. 248 loading_ = false; 249 break; 250 default: 251 NOTREACHED() << "Unknown nework state notification:" 252 << state_details->state(); 253 } 254 break; 255 } 256#endif 257 case NotificationType::LOAD_START: { 258 // Add this render_widget_host to the set of those we're waiting for 259 // paints on. We want to only record stats for paints that occur after 260 // a load has finished. 261 NavigationController* tab = Source<NavigationController>(source).ptr(); 262 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); 263 DCHECK(render_widget_host); 264 render_widget_hosts_loading_.insert(render_widget_host); 265 break; 266 } 267 case NotificationType::TAB_CONTENTS_DESTROYED: { 268 TabContents* tab_contents = Source<TabContents>(source).ptr(); 269 if (!got_first_paint_) { 270 render_widget_hosts_loading_.erase( 271 tab_contents->GetRenderWidgetHostView()->GetRenderWidgetHost()); 272 } 273 HandleTabClosedOrLoaded(&tab_contents->controller()); 274 break; 275 } 276 case NotificationType::LOAD_STOP: { 277 NavigationController* tab = Source<NavigationController>(source).ptr(); 278 render_widget_hosts_to_paint_.insert(GetRenderWidgetHost(tab)); 279 HandleTabClosedOrLoaded(tab); 280 break; 281 } 282 case NotificationType::RENDER_WIDGET_HOST_DID_PAINT: { 283 if (!got_first_paint_) { 284 RenderWidgetHost* render_widget_host = 285 Source<RenderWidgetHost>(source).ptr(); 286 if (render_widget_hosts_to_paint_.find(render_widget_host) != 287 render_widget_hosts_to_paint_.end()) { 288 // Got a paint for one of our renderers, so record time. 289 got_first_paint_ = true; 290 base::TimeDelta time_to_paint = 291 base::TimeTicks::Now() - restore_started_; 292 HISTOGRAM_CUSTOM_TIMES( 293 "SessionRestore.FirstTabPainted", 294 time_to_paint, 295 base::TimeDelta::FromMilliseconds(10), 296 base::TimeDelta::FromSeconds(100), 297 100); 298 // Record a time for the number of tabs, to help track down 299 // contention. 300 std::string time_for_count = 301 StringPrintf("SessionRestore.FirstTabPainted_%d", tab_count_); 302 scoped_refptr<base::Histogram> counter_for_count = 303 base::Histogram::FactoryTimeGet( 304 time_for_count, 305 base::TimeDelta::FromMilliseconds(10), 306 base::TimeDelta::FromSeconds(100), 307 100, 308 base::Histogram::kNoFlags); 309 counter_for_count->AddTime(time_to_paint); 310 } else if (render_widget_hosts_loading_.find(render_widget_host) == 311 render_widget_hosts_loading_.end()) { 312 // If this is a host for a tab we're not loading some other tab 313 // has rendered and there's no point tracking the time. This could 314 // happen because the user opened a different tab or restored tabs 315 // to an already existing browser and an existing tab painted. 316 got_first_paint_ = true; 317 } 318 } 319 break; 320 } 321 default: 322 NOTREACHED() << "Unknown notification received:" << type.value; 323 } 324 // Delete ourselves when we're not waiting for any more notifications. 325 if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && 326 tabs_loading_.empty() && tabs_to_load_.empty()) 327 delete this; 328} 329 330void TabLoader::RemoveTab(NavigationController* tab) { 331 registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED, 332 Source<TabContents>(tab->tab_contents())); 333 registrar_.Remove(this, NotificationType::LOAD_STOP, 334 Source<NavigationController>(tab)); 335 registrar_.Remove(this, NotificationType::LOAD_START, 336 Source<NavigationController>(tab)); 337 338 TabsLoading::iterator i = tabs_loading_.find(tab); 339 if (i != tabs_loading_.end()) 340 tabs_loading_.erase(i); 341 342 TabsToLoad::iterator j = 343 find(tabs_to_load_.begin(), tabs_to_load_.end(), tab); 344 if (j != tabs_to_load_.end()) 345 tabs_to_load_.erase(j); 346} 347 348void TabLoader::ForceLoadTimerFired() { 349 force_load_delay_ *= 2; 350 LoadNextTab(); 351} 352 353RenderWidgetHost* TabLoader::GetRenderWidgetHost(NavigationController* tab) { 354 TabContents* tab_contents = tab->tab_contents(); 355 if (tab_contents) { 356 RenderWidgetHostView* render_widget_host_view = 357 tab_contents->GetRenderWidgetHostView(); 358 if (render_widget_host_view) 359 return render_widget_host_view->GetRenderWidgetHost(); 360 } 361 return NULL; 362} 363 364void TabLoader::RegisterForNotifications(NavigationController* controller) { 365 registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED, 366 Source<TabContents>(controller->tab_contents())); 367 registrar_.Add(this, NotificationType::LOAD_STOP, 368 Source<NavigationController>(controller)); 369 registrar_.Add(this, NotificationType::LOAD_START, 370 Source<NavigationController>(controller)); 371 ++tab_count_; 372} 373 374void TabLoader::HandleTabClosedOrLoaded(NavigationController* tab) { 375 RemoveTab(tab); 376 if (loading_) 377 LoadNextTab(); 378 if (tabs_loading_.empty() && tabs_to_load_.empty()) { 379 base::TimeDelta time_to_load = 380 base::TimeTicks::Now() - restore_started_; 381 HISTOGRAM_CUSTOM_TIMES( 382 "SessionRestore.AllTabsLoaded", 383 time_to_load, 384 base::TimeDelta::FromMilliseconds(10), 385 base::TimeDelta::FromSeconds(100), 386 100); 387 // Record a time for the number of tabs, to help track down contention. 388 std::string time_for_count = 389 StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_); 390 scoped_refptr<base::Histogram> counter_for_count = 391 base::Histogram::FactoryTimeGet( 392 time_for_count, 393 base::TimeDelta::FromMilliseconds(10), 394 base::TimeDelta::FromSeconds(100), 395 100, 396 base::Histogram::kNoFlags); 397 counter_for_count->AddTime(time_to_load); 398 } 399} 400 401// SessionRestoreImpl --------------------------------------------------------- 402 403// SessionRestoreImpl is responsible for fetching the set of tabs to create 404// from SessionService. SessionRestoreImpl deletes itself when done. 405 406class SessionRestoreImpl : public NotificationObserver { 407 public: 408 SessionRestoreImpl(Profile* profile, 409 Browser* browser, 410 bool synchronous, 411 bool clobber_existing_window, 412 bool always_create_tabbed_browser, 413 const std::vector<GURL>& urls_to_open) 414 : profile_(profile), 415 browser_(browser), 416 synchronous_(synchronous), 417 clobber_existing_window_(clobber_existing_window), 418 always_create_tabbed_browser_(always_create_tabbed_browser), 419 urls_to_open_(urls_to_open), 420 restore_started_(base::TimeTicks::Now()) { 421 } 422 423 void Restore() { 424 SessionService* session_service = profile_->GetSessionService(); 425 DCHECK(session_service); 426 SessionService::SessionCallback* callback = 427 NewCallback(this, &SessionRestoreImpl::OnGotSession); 428 session_service->GetLastSession(&request_consumer_, callback); 429 430 if (synchronous_) { 431 bool old_state = MessageLoop::current()->NestableTasksAllowed(); 432 MessageLoop::current()->SetNestableTasksAllowed(true); 433 MessageLoop::current()->Run(); 434 MessageLoop::current()->SetNestableTasksAllowed(old_state); 435 ProcessSessionWindows(&windows_); 436 delete this; 437 return; 438 } 439 440 if (browser_) { 441 registrar_.Add(this, NotificationType::BROWSER_CLOSED, 442 Source<Browser>(browser_)); 443 } 444 } 445 446 // Restore window(s) from a foreign session. 447 void RestoreForeignSession( 448 std::vector<SessionWindow*>::const_iterator begin, 449 std::vector<SessionWindow*>::const_iterator end) { 450 StartTabCreation(); 451 // Create a browser instance to put the restored tabs in. 452 for (std::vector<SessionWindow*>::const_iterator i = begin; 453 i != end; ++i) { 454 Browser* browser = CreateRestoredBrowser( 455 static_cast<Browser::Type>((*i)->type), 456 (*i)->bounds, 457 (*i)->is_maximized); 458 459 // Restore and show the browser. 460 const int initial_tab_count = browser->tab_count(); 461 int selected_tab_index = (*i)->selected_tab_index; 462 RestoreTabsToBrowser(*(*i), browser, selected_tab_index); 463 ShowBrowser(browser, initial_tab_count, selected_tab_index); 464 tab_loader_->TabIsLoading( 465 &browser->GetSelectedTabContents()->controller()); 466 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count); 467 } 468 469 // Always create in a new window 470 FinishedTabCreation(true, true); 471 } 472 473 // Restore a single tab from a foreign session. 474 // Note: we currently restore the tab to the last active browser. 475 void RestoreForeignTab(const SessionTab& tab) { 476 StartTabCreation(); 477 Browser* current_browser = 478 browser_ ? browser_ : BrowserList::GetLastActive(); 479 RestoreTab(tab, current_browser->tab_count(), current_browser, true); 480 NotifySessionServiceOfRestoredTabs(current_browser, 481 current_browser->tab_count()); 482 FinishedTabCreation(true, true); 483 } 484 485 ~SessionRestoreImpl() { 486 STLDeleteElements(&windows_); 487 restoring = false; 488 } 489 490 virtual void Observe(NotificationType type, 491 const NotificationSource& source, 492 const NotificationDetails& details) { 493 switch (type.value) { 494 case NotificationType::BROWSER_CLOSED: 495 delete this; 496 return; 497 498 default: 499 NOTREACHED(); 500 break; 501 } 502 } 503 504 private: 505 // Invoked when beginning to create new tabs. Resets the tab_loader_. 506 void StartTabCreation() { 507 tab_loader_.reset(new TabLoader(restore_started_)); 508 } 509 510 // Invoked when done with creating all the tabs/browsers. 511 // 512 // |created_tabbed_browser| indicates whether a tabbed browser was created, 513 // or we used an existing tabbed browser. 514 // 515 // If successful, this begins loading tabs and deletes itself when all tabs 516 // have been loaded. 517 void FinishedTabCreation(bool succeeded, bool created_tabbed_browser) { 518 if (!created_tabbed_browser && always_create_tabbed_browser_) { 519 Browser* browser = Browser::Create(profile_); 520 if (urls_to_open_.empty()) { 521 // No tab browsers were created and no URLs were supplied on the command 522 // line. Add an empty URL, which is treated as opening the users home 523 // page. 524 urls_to_open_.push_back(GURL()); 525 } 526 AppendURLsToBrowser(browser, urls_to_open_); 527 browser->window()->Show(); 528 } 529 530 if (succeeded) { 531 DCHECK(tab_loader_.get()); 532 // TabLoader delets itself when done loading. 533 tab_loader_.release()->StartLoading(); 534 } 535 536 if (!synchronous_) { 537 // If we're not synchronous we need to delete ourself. 538 // NOTE: we must use DeleteLater here as most likely we're in a callback 539 // from the history service which doesn't deal well with deleting the 540 // object it is notifying. 541 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 542 } 543 } 544 545 void OnGotSession(SessionService::Handle handle, 546 std::vector<SessionWindow*>* windows) { 547 if (synchronous_) { 548 // See comment above windows_ as to why we don't process immediately. 549 windows_.swap(*windows); 550 MessageLoop::current()->Quit(); 551 return; 552 } 553 554 ProcessSessionWindows(windows); 555 } 556 557 void ProcessSessionWindows(std::vector<SessionWindow*>* windows) { 558 if (windows->empty()) { 559 // Restore was unsuccessful. 560 FinishedTabCreation(false, false); 561 return; 562 } 563 564 StartTabCreation(); 565 566 Browser* current_browser = 567 browser_ ? browser_ : BrowserList::GetLastActive(); 568 // After the for loop this contains the last TABBED_BROWSER. Is null if no 569 // tabbed browsers exist. 570 Browser* last_browser = NULL; 571 bool has_tabbed_browser = false; 572 for (std::vector<SessionWindow*>::iterator i = windows->begin(); 573 i != windows->end(); ++i) { 574 Browser* browser = NULL; 575 if (!has_tabbed_browser && (*i)->type == Browser::TYPE_NORMAL) 576 has_tabbed_browser = true; 577 if (i == windows->begin() && (*i)->type == Browser::TYPE_NORMAL && 578 !clobber_existing_window_) { 579 // If there is an open tabbed browser window, use it. Otherwise fall 580 // through and create a new one. 581 browser = current_browser; 582 if (browser && (browser->type() != Browser::TYPE_NORMAL || 583 browser->profile()->IsOffTheRecord())) { 584 browser = NULL; 585 } 586 } 587 if (!browser) { 588 browser = CreateRestoredBrowser( 589 static_cast<Browser::Type>((*i)->type), 590 (*i)->bounds, 591 (*i)->is_maximized); 592 } 593 if ((*i)->type == Browser::TYPE_NORMAL) 594 last_browser = browser; 595 const int initial_tab_count = browser->tab_count(); 596 int selected_tab_index = (*i)->selected_tab_index; 597 RestoreTabsToBrowser(*(*i), browser, selected_tab_index); 598 ShowBrowser(browser, initial_tab_count, selected_tab_index); 599 tab_loader_->TabIsLoading( 600 &browser->GetSelectedTabContents()->controller()); 601 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count); 602 } 603 604 // If we're restoring a session as the result of a crash and the session 605 // included at least one tabbed browser, then close the browser window 606 // that was opened when the user clicked to restore the session. 607 if (clobber_existing_window_ && current_browser && has_tabbed_browser && 608 current_browser->type() == Browser::TYPE_NORMAL) { 609 current_browser->CloseAllTabs(); 610 } 611 if (last_browser && !urls_to_open_.empty()) 612 AppendURLsToBrowser(last_browser, urls_to_open_); 613 // If last_browser is NULL and urls_to_open_ is non-empty, 614 // FinishedTabCreation will create a new TabbedBrowser and add the urls to 615 // it. 616 FinishedTabCreation(true, has_tabbed_browser); 617 } 618 619 void RestoreTabsToBrowser(const SessionWindow& window, 620 Browser* browser, 621 int selected_tab_index) { 622 DCHECK(!window.tabs.empty()); 623 for (std::vector<SessionTab*>::const_iterator i = window.tabs.begin(); 624 i != window.tabs.end(); ++i) { 625 const SessionTab& tab = *(*i); 626 const int tab_index = static_cast<int>(i - window.tabs.begin()); 627 // Don't schedule a load for the selected tab, as ShowBrowser() will 628 // already have done that. 629 RestoreTab(tab, tab_index, browser, tab_index != selected_tab_index); 630 } 631 } 632 633 void RestoreTab(const SessionTab& tab, 634 const int tab_index, 635 Browser* browser, 636 bool schedule_load) { 637 DCHECK(!tab.navigations.empty()); 638 int selected_index = tab.current_navigation_index; 639 selected_index = std::max( 640 0, 641 std::min(selected_index, 642 static_cast<int>(tab.navigations.size() - 1))); 643 TabContents* tab_contents = 644 browser->AddRestoredTab(tab.navigations, 645 tab_index, 646 selected_index, 647 tab.extension_app_id, 648 false, 649 tab.pinned, 650 true, 651 NULL); 652 if (schedule_load) 653 tab_loader_->ScheduleLoad(&tab_contents->controller()); 654 } 655 656 Browser* CreateRestoredBrowser(Browser::Type type, 657 gfx::Rect bounds, 658 bool is_maximized) { 659 Browser* browser = new Browser(type, profile_); 660 browser->set_override_bounds(bounds); 661 browser->set_maximized_state(is_maximized ? 662 Browser::MAXIMIZED_STATE_MAXIMIZED : 663 Browser::MAXIMIZED_STATE_UNMAXIMIZED); 664 browser->CreateBrowserWindow(); 665 return browser; 666 } 667 668 void ShowBrowser(Browser* browser, 669 int initial_tab_count, 670 int selected_session_index) { 671 if (browser_ == browser) { 672 browser->SelectTabContentsAt(browser->tab_count() - 1, true); 673 return; 674 } 675 676 DCHECK(browser); 677 DCHECK(browser->tab_count()); 678 browser->SelectTabContentsAt( 679 std::min(initial_tab_count + std::max(0, selected_session_index), 680 browser->tab_count() - 1), true); 681 browser->window()->Show(); 682 // TODO(jcampan): http://crbug.com/8123 we should not need to set the 683 // initial focus explicitly. 684 browser->GetSelectedTabContents()->view()->SetInitialFocus(); 685 } 686 687 // Appends the urls in |urls| to |browser|. 688 void AppendURLsToBrowser(Browser* browser, 689 const std::vector<GURL>& urls) { 690 for (size_t i = 0; i < urls.size(); ++i) { 691 int add_types = TabStripModel::ADD_FORCE_INDEX; 692 if (i == 0) 693 add_types |= TabStripModel::ADD_SELECTED; 694 int index = browser->GetIndexForInsertionDuringRestore(i); 695 browser::NavigateParams params(browser, urls[i], 696 PageTransition::START_PAGE); 697 params.disposition = i == 0 ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB; 698 params.tabstrip_index = index; 699 params.tabstrip_add_types = add_types; 700 browser::Navigate(¶ms); 701 } 702 } 703 704 // Invokes TabRestored on the SessionService for all tabs in browser after 705 // initial_count. 706 void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) { 707 SessionService* session_service = profile_->GetSessionService(); 708 for (int i = initial_count; i < browser->tab_count(); ++i) 709 session_service->TabRestored(&browser->GetTabContentsAt(i)->controller(), 710 browser->tabstrip_model()->IsTabPinned(i)); 711 } 712 713 // The profile to create the sessions for. 714 Profile* profile_; 715 716 // The first browser to restore to, may be null. 717 Browser* browser_; 718 719 // Whether or not restore is synchronous. 720 const bool synchronous_; 721 722 // See description in RestoreSession (in .h). 723 const bool clobber_existing_window_; 724 725 // If true and there is an error or there are no windows to restore, we 726 // create a tabbed browser anyway. This is used on startup to make sure at 727 // at least one window is created. 728 const bool always_create_tabbed_browser_; 729 730 // Set of URLs to open in addition to those restored from the session. 731 std::vector<GURL> urls_to_open_; 732 733 // Used to get the session. 734 CancelableRequestConsumer request_consumer_; 735 736 // Responsible for loading the tabs. 737 scoped_ptr<TabLoader> tab_loader_; 738 739 // When synchronous we run a nested message loop. To avoid creating windows 740 // from the nested message loop (which can make exiting the nested message 741 // loop take a while) we cache the SessionWindows here and create the actual 742 // windows when the nested message loop exits. 743 std::vector<SessionWindow*> windows_; 744 745 NotificationRegistrar registrar_; 746 747 // The time we started the restore. 748 base::TimeTicks restore_started_; 749}; 750 751} // namespace 752 753// SessionRestore ------------------------------------------------------------- 754 755static void Restore(Profile* profile, 756 Browser* browser, 757 bool synchronous, 758 bool clobber_existing_window, 759 bool always_create_tabbed_browser, 760 const std::vector<GURL>& urls_to_open) { 761#if defined(OS_CHROMEOS) 762 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 763 "SessionRestoreStarted", false); 764#endif 765 DCHECK(profile); 766 // Always restore from the original profile (incognito profiles have no 767 // session service). 768 profile = profile->GetOriginalProfile(); 769 if (!profile->GetSessionService()) { 770 NOTREACHED(); 771 return; 772 } 773 restoring = true; 774 profile->set_restored_last_session(true); 775 // SessionRestoreImpl takes care of deleting itself when done. 776 SessionRestoreImpl* restorer = 777 new SessionRestoreImpl(profile, browser, synchronous, 778 clobber_existing_window, 779 always_create_tabbed_browser, urls_to_open); 780 restorer->Restore(); 781} 782 783// static 784void SessionRestore::RestoreSession(Profile* profile, 785 Browser* browser, 786 bool clobber_existing_window, 787 bool always_create_tabbed_browser, 788 const std::vector<GURL>& urls_to_open) { 789 Restore(profile, browser, false, clobber_existing_window, 790 always_create_tabbed_browser, urls_to_open); 791} 792 793// static 794void SessionRestore::RestoreForeignSessionWindows( 795 Profile* profile, 796 std::vector<SessionWindow*>::const_iterator begin, 797 std::vector<SessionWindow*>::const_iterator end) { 798 // Create a SessionRestore object to eventually restore the tabs. 799 std::vector<GURL> gurls; 800 SessionRestoreImpl restorer(profile, 801 static_cast<Browser*>(NULL), true, false, true, gurls); 802 restorer.RestoreForeignSession(begin, end); 803} 804 805// static 806void SessionRestore::RestoreForeignSessionTab(Profile* profile, 807 const SessionTab& tab) { 808 // Create a SessionRestore object to eventually restore the tabs. 809 std::vector<GURL> gurls; 810 SessionRestoreImpl restorer(profile, 811 static_cast<Browser*>(NULL), true, false, true, gurls); 812 restorer.RestoreForeignTab(tab); 813} 814 815// static 816void SessionRestore::RestoreSessionSynchronously( 817 Profile* profile, 818 const std::vector<GURL>& urls_to_open) { 819 Restore(profile, NULL, true, false, true, urls_to_open); 820} 821 822// static 823bool SessionRestore::IsRestoring() { 824 return restoring; 825} 826