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 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 <string> 11 12 #include "base/bind.h" 13 #include "base/bind_helpers.h" 14 #include "base/callback.h" 15 #include "base/command_line.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/memory/scoped_vector.h" 18 #include "base/metrics/histogram.h" 19 #include "base/platform_file.h" 20 #include "base/stl_util.h" 21 #include "base/strings/stringprintf.h" 22 #include "chrome/browser/browser_process.h" 23 #include "chrome/browser/chrome_notification_types.h" 24 #include "chrome/browser/extensions/extension_service.h" 25 #include "chrome/browser/performance_monitor/startup_timer.h" 26 #include "chrome/browser/profiles/profile.h" 27 #include "chrome/browser/sessions/session_service.h" 28 #include "chrome/browser/sessions/session_service_factory.h" 29 #include "chrome/browser/sessions/session_types.h" 30 #include "chrome/browser/ui/browser.h" 31 #include "chrome/browser/ui/browser_finder.h" 32 #include "chrome/browser/ui/browser_navigator.h" 33 #include "chrome/browser/ui/browser_tabrestore.h" 34 #include "chrome/browser/ui/browser_tabstrip.h" 35 #include "chrome/browser/ui/browser_window.h" 36 #include "chrome/browser/ui/tabs/tab_strip_model.h" 37 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h" 38 #include "chrome/common/cancelable_task_tracker.h" 39 #include "content/public/browser/child_process_security_policy.h" 40 #include "content/public/browser/dom_storage_context.h" 41 #include "content/public/browser/navigation_controller.h" 42 #include "content/public/browser/notification_registrar.h" 43 #include "content/public/browser/notification_service.h" 44 #include "content/public/browser/render_process_host.h" 45 #include "content/public/browser/render_widget_host.h" 46 #include "content/public/browser/render_widget_host_view.h" 47 #include "content/public/browser/session_storage_namespace.h" 48 #include "content/public/browser/storage_partition.h" 49 #include "content/public/browser/web_contents.h" 50 #include "content/public/browser/web_contents_view.h" 51 #include "net/base/network_change_notifier.h" 52 53 #if defined(OS_CHROMEOS) 54 #include "chrome/browser/chromeos/boot_times_loader.h" 55 #endif 56 57 #if defined(OS_WIN) 58 #include "win8/util/win8_util.h" 59 #endif 60 61 #if defined(USE_ASH) 62 #include "ash/wm/window_util.h" 63 #endif 64 using content::NavigationController; 65 using content::RenderWidgetHost; 66 using content::WebContents; 67 68 namespace { 69 70 class SessionRestoreImpl; 71 class TabLoader; 72 73 TabLoader* shared_tab_loader = NULL; 74 75 // Pointers to SessionRestoreImpls which are currently restoring the session. 76 std::set<SessionRestoreImpl*>* active_session_restorers = NULL; 77 78 // TabLoader ------------------------------------------------------------------ 79 80 // Initial delay (see class decription for details). 81 static const int kInitialDelayTimerMS = 100; 82 83 // TabLoader is responsible for loading tabs after session restore creates 84 // tabs. New tabs are loaded after the current tab finishes loading, or a delay 85 // is reached (initially kInitialDelayTimerMS). If the delay is reached before 86 // a tab finishes loading a new tab is loaded and the time of the delay 87 // doubled. 88 // 89 // TabLoader keeps a reference to itself when it's loading. When it has finished 90 // loading, it drops the reference. If another profile is restored while the 91 // TabLoader is loading, it will schedule its tabs to get loaded by the same 92 // TabLoader. When doing the scheduling, it holds a reference to the TabLoader. 93 // 94 // This is not part of SessionRestoreImpl so that synchronous destruction 95 // of SessionRestoreImpl doesn't have timing problems. 96 class TabLoader : public content::NotificationObserver, 97 public net::NetworkChangeNotifier::ConnectionTypeObserver, 98 public base::RefCounted<TabLoader> { 99 public: 100 // Retrieves a pointer to the TabLoader instance shared between profiles, or 101 // creates a new TabLoader if it doesn't exist. If a TabLoader is created, its 102 // starting timestamp is set to |restore_started|. 103 static TabLoader* GetTabLoader(base::TimeTicks restore_started); 104 105 // Schedules a tab for loading. 106 void ScheduleLoad(NavigationController* controller); 107 108 // Notifies the loader that a tab has been scheduled for loading through 109 // some other mechanism. 110 void TabIsLoading(NavigationController* controller); 111 112 // Invokes |LoadNextTab| to load a tab. 113 // 114 // This must be invoked once to start loading. 115 void StartLoading(); 116 117 private: 118 friend class base::RefCounted<TabLoader>; 119 120 typedef std::set<NavigationController*> TabsLoading; 121 typedef std::list<NavigationController*> TabsToLoad; 122 typedef std::set<RenderWidgetHost*> RenderWidgetHostSet; 123 124 explicit TabLoader(base::TimeTicks restore_started); 125 virtual ~TabLoader(); 126 127 // Loads the next tab. If there are no more tabs to load this deletes itself, 128 // otherwise |force_load_timer_| is restarted. 129 void LoadNextTab(); 130 131 // NotificationObserver method. Removes the specified tab and loads the next 132 // tab. 133 virtual void Observe(int type, 134 const content::NotificationSource& source, 135 const content::NotificationDetails& details) OVERRIDE; 136 137 // net::NetworkChangeNotifier::ConnectionTypeObserver overrides. 138 virtual void OnConnectionTypeChanged( 139 net::NetworkChangeNotifier::ConnectionType type) OVERRIDE; 140 141 // Removes the listeners from the specified tab and removes the tab from 142 // the set of tabs to load and list of tabs we're waiting to get a load 143 // from. 144 void RemoveTab(NavigationController* tab); 145 146 // Invoked from |force_load_timer_|. Doubles |force_load_delay_| and invokes 147 // |LoadNextTab| to load the next tab 148 void ForceLoadTimerFired(); 149 150 // Returns the RenderWidgetHost associated with a tab if there is one, 151 // NULL otherwise. 152 static RenderWidgetHost* GetRenderWidgetHost(NavigationController* tab); 153 154 // Register for necessary notifications on a tab navigation controller. 155 void RegisterForNotifications(NavigationController* controller); 156 157 // Called when a tab goes away or a load completes. 158 void HandleTabClosedOrLoaded(NavigationController* controller); 159 160 content::NotificationRegistrar registrar_; 161 162 // Current delay before a new tab is loaded. See class description for 163 // details. 164 int64 force_load_delay_; 165 166 // Has Load been invoked? 167 bool loading_; 168 169 // Have we recorded the times for a tab paint? 170 bool got_first_paint_; 171 172 // The set of tabs we've initiated loading on. This does NOT include the 173 // selected tabs. 174 TabsLoading tabs_loading_; 175 176 // The tabs we need to load. 177 TabsToLoad tabs_to_load_; 178 179 // The renderers we have started loading into. 180 RenderWidgetHostSet render_widget_hosts_loading_; 181 182 // The renderers we have loaded and are waiting on to paint. 183 RenderWidgetHostSet render_widget_hosts_to_paint_; 184 185 // The number of tabs that have been restored. 186 int tab_count_; 187 188 base::OneShotTimer<TabLoader> force_load_timer_; 189 190 // The time the restore process started. 191 base::TimeTicks restore_started_; 192 193 // Max number of tabs that were loaded in parallel (for metrics). 194 size_t max_parallel_tab_loads_; 195 196 // For keeping TabLoader alive while it's loading even if no 197 // SessionRestoreImpls reference it. 198 scoped_refptr<TabLoader> this_retainer_; 199 200 DISALLOW_COPY_AND_ASSIGN(TabLoader); 201 }; 202 203 // static 204 TabLoader* TabLoader::GetTabLoader(base::TimeTicks restore_started) { 205 if (!shared_tab_loader) 206 shared_tab_loader = new TabLoader(restore_started); 207 return shared_tab_loader; 208 } 209 210 void TabLoader::ScheduleLoad(NavigationController* controller) { 211 DCHECK(controller); 212 DCHECK(find(tabs_to_load_.begin(), tabs_to_load_.end(), controller) == 213 tabs_to_load_.end()); 214 tabs_to_load_.push_back(controller); 215 RegisterForNotifications(controller); 216 } 217 218 void TabLoader::TabIsLoading(NavigationController* controller) { 219 DCHECK(controller); 220 DCHECK(find(tabs_loading_.begin(), tabs_loading_.end(), controller) == 221 tabs_loading_.end()); 222 tabs_loading_.insert(controller); 223 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(controller); 224 DCHECK(render_widget_host); 225 render_widget_hosts_loading_.insert(render_widget_host); 226 RegisterForNotifications(controller); 227 } 228 229 void TabLoader::StartLoading() { 230 // When multiple profiles are using the same TabLoader, another profile might 231 // already have started loading. In that case, the tabs scheduled for loading 232 // by this profile are already in the loading queue, and they will get loaded 233 // eventually. 234 if (loading_) 235 return; 236 registrar_.Add( 237 this, 238 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, 239 content::NotificationService::AllSources()); 240 this_retainer_ = this; 241 #if defined(OS_CHROMEOS) 242 if (!net::NetworkChangeNotifier::IsOffline()) { 243 loading_ = true; 244 LoadNextTab(); 245 } else { 246 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); 247 } 248 #else 249 loading_ = true; 250 LoadNextTab(); 251 #endif 252 } 253 254 TabLoader::TabLoader(base::TimeTicks restore_started) 255 : force_load_delay_(kInitialDelayTimerMS), 256 loading_(false), 257 got_first_paint_(false), 258 tab_count_(0), 259 restore_started_(restore_started), 260 max_parallel_tab_loads_(0) { 261 } 262 263 TabLoader::~TabLoader() { 264 DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && 265 tabs_loading_.empty() && tabs_to_load_.empty()); 266 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); 267 shared_tab_loader = NULL; 268 } 269 270 void TabLoader::LoadNextTab() { 271 if (!tabs_to_load_.empty()) { 272 NavigationController* tab = tabs_to_load_.front(); 273 DCHECK(tab); 274 tabs_loading_.insert(tab); 275 if (tabs_loading_.size() > max_parallel_tab_loads_) 276 max_parallel_tab_loads_ = tabs_loading_.size(); 277 tabs_to_load_.pop_front(); 278 tab->LoadIfNecessary(); 279 content::WebContents* contents = tab->GetWebContents(); 280 if (contents) { 281 Browser* browser = chrome::FindBrowserWithWebContents(contents); 282 if (browser && 283 browser->tab_strip_model()->GetActiveWebContents() != contents) { 284 // By default tabs are marked as visible. As only the active tab is 285 // visible we need to explicitly tell non-active tabs they are hidden. 286 // Without this call non-active tabs are not marked as backgrounded. 287 // 288 // NOTE: We need to do this here rather than when the tab is added to 289 // the Browser as at that time not everything has been created, so that 290 // the call would do nothing. 291 contents->WasHidden(); 292 } 293 } 294 } 295 296 if (!tabs_to_load_.empty()) { 297 force_load_timer_.Stop(); 298 // Each time we load a tab we also set a timer to force us to start loading 299 // the next tab if this one doesn't load quickly enough. 300 force_load_timer_.Start(FROM_HERE, 301 base::TimeDelta::FromMilliseconds(force_load_delay_), 302 this, &TabLoader::ForceLoadTimerFired); 303 } 304 305 // When the session restore is done synchronously, notification is sent from 306 // SessionRestoreImpl::Restore . 307 if (tabs_to_load_.empty() && !SessionRestore::IsRestoringSynchronously()) { 308 content::NotificationService::current()->Notify( 309 chrome::NOTIFICATION_SESSION_RESTORE_DONE, 310 content::NotificationService::AllSources(), 311 content::NotificationService::NoDetails()); 312 } 313 } 314 315 void TabLoader::Observe(int type, 316 const content::NotificationSource& source, 317 const content::NotificationDetails& details) { 318 switch (type) { 319 case content::NOTIFICATION_LOAD_START: { 320 // Add this render_widget_host to the set of those we're waiting for 321 // paints on. We want to only record stats for paints that occur after 322 // a load has finished. 323 NavigationController* tab = 324 content::Source<NavigationController>(source).ptr(); 325 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); 326 DCHECK(render_widget_host); 327 render_widget_hosts_loading_.insert(render_widget_host); 328 break; 329 } 330 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { 331 WebContents* web_contents = content::Source<WebContents>(source).ptr(); 332 if (!got_first_paint_) { 333 RenderWidgetHost* render_widget_host = 334 GetRenderWidgetHost(&web_contents->GetController()); 335 render_widget_hosts_loading_.erase(render_widget_host); 336 } 337 HandleTabClosedOrLoaded(&web_contents->GetController()); 338 break; 339 } 340 case content::NOTIFICATION_LOAD_STOP: { 341 NavigationController* tab = 342 content::Source<NavigationController>(source).ptr(); 343 render_widget_hosts_to_paint_.insert(GetRenderWidgetHost(tab)); 344 HandleTabClosedOrLoaded(tab); 345 break; 346 } 347 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: { 348 RenderWidgetHost* render_widget_host = 349 content::Source<RenderWidgetHost>(source).ptr(); 350 if (!got_first_paint_ && render_widget_host->GetView() && 351 render_widget_host->GetView()->IsShowing()) { 352 if (render_widget_hosts_to_paint_.find(render_widget_host) != 353 render_widget_hosts_to_paint_.end()) { 354 // Got a paint for one of our renderers, so record time. 355 got_first_paint_ = true; 356 base::TimeDelta time_to_paint = 357 base::TimeTicks::Now() - restore_started_; 358 UMA_HISTOGRAM_CUSTOM_TIMES( 359 "SessionRestore.FirstTabPainted", 360 time_to_paint, 361 base::TimeDelta::FromMilliseconds(10), 362 base::TimeDelta::FromSeconds(100), 363 100); 364 // Record a time for the number of tabs, to help track down 365 // contention. 366 std::string time_for_count = 367 base::StringPrintf("SessionRestore.FirstTabPainted_%d", 368 tab_count_); 369 base::HistogramBase* counter_for_count = 370 base::Histogram::FactoryTimeGet( 371 time_for_count, 372 base::TimeDelta::FromMilliseconds(10), 373 base::TimeDelta::FromSeconds(100), 374 100, 375 base::Histogram::kUmaTargetedHistogramFlag); 376 counter_for_count->AddTime(time_to_paint); 377 } else if (render_widget_hosts_loading_.find(render_widget_host) == 378 render_widget_hosts_loading_.end()) { 379 // If this is a host for a tab we're not loading some other tab 380 // has rendered and there's no point tracking the time. This could 381 // happen because the user opened a different tab or restored tabs 382 // to an already existing browser and an existing tab painted. 383 got_first_paint_ = true; 384 } 385 } 386 break; 387 } 388 default: 389 NOTREACHED() << "Unknown notification received:" << type; 390 } 391 // Delete ourselves when we're not waiting for any more notifications. If this 392 // was not the last reference, a SessionRestoreImpl holding a reference will 393 // eventually call StartLoading (which assigns this_retainer_), or drop the 394 // reference without initiating a load. 395 if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && 396 tabs_loading_.empty() && tabs_to_load_.empty()) 397 this_retainer_ = NULL; 398 } 399 400 void TabLoader::OnConnectionTypeChanged( 401 net::NetworkChangeNotifier::ConnectionType type) { 402 if (type != net::NetworkChangeNotifier::CONNECTION_NONE) { 403 if (!loading_) { 404 loading_ = true; 405 LoadNextTab(); 406 } 407 } else { 408 loading_ = false; 409 } 410 } 411 412 void TabLoader::RemoveTab(NavigationController* tab) { 413 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 414 content::Source<WebContents>(tab->GetWebContents())); 415 registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP, 416 content::Source<NavigationController>(tab)); 417 registrar_.Remove(this, content::NOTIFICATION_LOAD_START, 418 content::Source<NavigationController>(tab)); 419 420 TabsLoading::iterator i = tabs_loading_.find(tab); 421 if (i != tabs_loading_.end()) 422 tabs_loading_.erase(i); 423 424 TabsToLoad::iterator j = 425 find(tabs_to_load_.begin(), tabs_to_load_.end(), tab); 426 if (j != tabs_to_load_.end()) 427 tabs_to_load_.erase(j); 428 } 429 430 void TabLoader::ForceLoadTimerFired() { 431 force_load_delay_ *= 2; 432 LoadNextTab(); 433 } 434 435 RenderWidgetHost* TabLoader::GetRenderWidgetHost(NavigationController* tab) { 436 WebContents* web_contents = tab->GetWebContents(); 437 if (web_contents) { 438 content::RenderWidgetHostView* render_widget_host_view = 439 web_contents->GetRenderWidgetHostView(); 440 if (render_widget_host_view) 441 return render_widget_host_view->GetRenderWidgetHost(); 442 } 443 return NULL; 444 } 445 446 void TabLoader::RegisterForNotifications(NavigationController* controller) { 447 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 448 content::Source<WebContents>(controller->GetWebContents())); 449 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 450 content::Source<NavigationController>(controller)); 451 registrar_.Add(this, content::NOTIFICATION_LOAD_START, 452 content::Source<NavigationController>(controller)); 453 ++tab_count_; 454 } 455 456 void TabLoader::HandleTabClosedOrLoaded(NavigationController* tab) { 457 RemoveTab(tab); 458 if (loading_) 459 LoadNextTab(); 460 if (tabs_loading_.empty() && tabs_to_load_.empty()) { 461 base::TimeDelta time_to_load = 462 base::TimeTicks::Now() - restore_started_; 463 performance_monitor::StartupTimer::SetElapsedSessionRestoreTime( 464 time_to_load); 465 UMA_HISTOGRAM_CUSTOM_TIMES( 466 "SessionRestore.AllTabsLoaded", 467 time_to_load, 468 base::TimeDelta::FromMilliseconds(10), 469 base::TimeDelta::FromSeconds(100), 470 100); 471 // Record a time for the number of tabs, to help track down contention. 472 std::string time_for_count = 473 base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_); 474 base::HistogramBase* counter_for_count = 475 base::Histogram::FactoryTimeGet( 476 time_for_count, 477 base::TimeDelta::FromMilliseconds(10), 478 base::TimeDelta::FromSeconds(100), 479 100, 480 base::Histogram::kUmaTargetedHistogramFlag); 481 counter_for_count->AddTime(time_to_load); 482 483 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads", 484 max_parallel_tab_loads_); 485 } 486 } 487 488 // SessionRestoreImpl --------------------------------------------------------- 489 490 // SessionRestoreImpl is responsible for fetching the set of tabs to create 491 // from SessionService. SessionRestoreImpl deletes itself when done. 492 493 class SessionRestoreImpl : public content::NotificationObserver { 494 public: 495 SessionRestoreImpl(Profile* profile, 496 Browser* browser, 497 chrome::HostDesktopType host_desktop_type, 498 bool synchronous, 499 bool clobber_existing_tab, 500 bool always_create_tabbed_browser, 501 const std::vector<GURL>& urls_to_open) 502 : profile_(profile), 503 browser_(browser), 504 host_desktop_type_(host_desktop_type), 505 synchronous_(synchronous), 506 clobber_existing_tab_(clobber_existing_tab), 507 always_create_tabbed_browser_(always_create_tabbed_browser), 508 urls_to_open_(urls_to_open), 509 active_window_id_(0), 510 restore_started_(base::TimeTicks::Now()), 511 browser_shown_(false) { 512 // For sanity's sake, if |browser| is non-null: force |host_desktop_type| to 513 // be the same as |browser|'s desktop type. 514 DCHECK(!browser || browser->host_desktop_type() == host_desktop_type); 515 516 if (active_session_restorers == NULL) 517 active_session_restorers = new std::set<SessionRestoreImpl*>(); 518 519 // Only one SessionRestoreImpl should be operating on the profile at the 520 // same time. 521 std::set<SessionRestoreImpl*>::const_iterator it; 522 for (it = active_session_restorers->begin(); 523 it != active_session_restorers->end(); ++it) { 524 if ((*it)->profile_ == profile) 525 break; 526 } 527 DCHECK(it == active_session_restorers->end()); 528 529 active_session_restorers->insert(this); 530 531 // When asynchronous its possible for there to be no windows. To make sure 532 // Chrome doesn't prematurely exit AddRef the process. We'll release in the 533 // destructor when restore is done. 534 g_browser_process->AddRefModule(); 535 } 536 537 bool synchronous() const { return synchronous_; } 538 539 Browser* Restore() { 540 SessionService* session_service = 541 SessionServiceFactory::GetForProfile(profile_); 542 DCHECK(session_service); 543 session_service->GetLastSession( 544 base::Bind(&SessionRestoreImpl::OnGotSession, base::Unretained(this)), 545 &cancelable_task_tracker_); 546 547 if (synchronous_) { 548 { 549 base::MessageLoop::ScopedNestableTaskAllower allow( 550 base::MessageLoop::current()); 551 base::MessageLoop::current()->Run(); 552 } 553 Browser* browser = ProcessSessionWindows(&windows_, active_window_id_); 554 delete this; 555 content::NotificationService::current()->Notify( 556 chrome::NOTIFICATION_SESSION_RESTORE_DONE, 557 content::NotificationService::AllSources(), 558 content::NotificationService::NoDetails()); 559 return browser; 560 } 561 562 if (browser_) { 563 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, 564 content::Source<Browser>(browser_)); 565 } 566 567 return browser_; 568 } 569 570 // Restore window(s) from a foreign session. Returns newly created Browsers. 571 std::vector<Browser*> RestoreForeignSession( 572 std::vector<const SessionWindow*>::const_iterator begin, 573 std::vector<const SessionWindow*>::const_iterator end) { 574 StartTabCreation(); 575 std::vector<Browser*> browsers; 576 // Create a browser instance to put the restored tabs in. 577 for (std::vector<const SessionWindow*>::const_iterator i = begin; 578 i != end; ++i) { 579 Browser* browser = CreateRestoredBrowser( 580 static_cast<Browser::Type>((*i)->type), 581 (*i)->bounds, 582 (*i)->show_state, 583 (*i)->app_name); 584 browsers.push_back(browser); 585 586 // Restore and show the browser. 587 const int initial_tab_count = 0; 588 int selected_tab_index = std::max( 589 0, 590 std::min((*i)->selected_tab_index, 591 static_cast<int>((*i)->tabs.size()) - 1)); 592 RestoreTabsToBrowser(*(*i), browser, initial_tab_count, 593 selected_tab_index); 594 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count); 595 } 596 597 // Always create in a new window 598 FinishedTabCreation(true, true); 599 return browsers; 600 } 601 602 // Restore a single tab from a foreign session. 603 // Opens in the tab in the last active browser, unless disposition is 604 // NEW_WINDOW, in which case the tab will be opened in a new browser. Returns 605 // the WebContents of the restored tab. 606 WebContents* RestoreForeignTab(const SessionTab& tab, 607 WindowOpenDisposition disposition) { 608 DCHECK(!tab.navigations.empty()); 609 int selected_index = tab.current_navigation_index; 610 selected_index = std::max( 611 0, 612 std::min(selected_index, 613 static_cast<int>(tab.navigations.size() - 1))); 614 615 bool use_new_window = disposition == NEW_WINDOW; 616 617 Browser* browser = use_new_window ? 618 new Browser(Browser::CreateParams(profile_, host_desktop_type_)) : 619 browser_; 620 621 RecordAppLaunchForTab(browser, tab, selected_index); 622 623 WebContents* web_contents; 624 if (disposition == CURRENT_TAB) { 625 DCHECK(!use_new_window); 626 web_contents = chrome::ReplaceRestoredTab(browser, 627 tab.navigations, 628 selected_index, 629 true, 630 tab.extension_app_id, 631 NULL, 632 tab.user_agent_override); 633 } else { 634 int tab_index = 635 use_new_window ? 0 : browser->tab_strip_model()->active_index() + 1; 636 web_contents = chrome::AddRestoredTab( 637 browser, 638 tab.navigations, 639 tab_index, 640 selected_index, 641 tab.extension_app_id, 642 disposition == NEW_FOREGROUND_TAB, // selected 643 tab.pinned, 644 true, 645 NULL, 646 tab.user_agent_override); 647 // Start loading the tab immediately. 648 web_contents->GetController().LoadIfNecessary(); 649 } 650 651 if (use_new_window) { 652 browser->tab_strip_model()->ActivateTabAt(0, true); 653 browser->window()->Show(); 654 } 655 NotifySessionServiceOfRestoredTabs(browser, 656 browser->tab_strip_model()->count()); 657 658 // Since FinishedTabCreation() is not called here, |this| will leak if we 659 // are not in sychronous mode. 660 DCHECK(synchronous_); 661 return web_contents; 662 } 663 664 virtual ~SessionRestoreImpl() { 665 STLDeleteElements(&windows_); 666 667 active_session_restorers->erase(this); 668 if (active_session_restorers->empty()) { 669 delete active_session_restorers; 670 active_session_restorers = NULL; 671 } 672 673 g_browser_process->ReleaseModule(); 674 } 675 676 virtual void Observe(int type, 677 const content::NotificationSource& source, 678 const content::NotificationDetails& details) OVERRIDE { 679 switch (type) { 680 case chrome::NOTIFICATION_BROWSER_CLOSED: 681 delete this; 682 return; 683 684 default: 685 NOTREACHED(); 686 break; 687 } 688 } 689 690 Profile* profile() { return profile_; } 691 692 private: 693 // Invoked when beginning to create new tabs. Resets the tab_loader_. 694 void StartTabCreation() { 695 tab_loader_ = TabLoader::GetTabLoader(restore_started_); 696 } 697 698 // Invoked when done with creating all the tabs/browsers. 699 // 700 // |created_tabbed_browser| indicates whether a tabbed browser was created, 701 // or we used an existing tabbed browser. 702 // 703 // If successful, this begins loading tabs and deletes itself when all tabs 704 // have been loaded. 705 // 706 // Returns the Browser that was created, if any. 707 Browser* FinishedTabCreation(bool succeeded, bool created_tabbed_browser) { 708 Browser* browser = NULL; 709 if (!created_tabbed_browser && always_create_tabbed_browser_) { 710 browser = new Browser(Browser::CreateParams(profile_, 711 host_desktop_type_)); 712 if (urls_to_open_.empty()) { 713 // No tab browsers were created and no URLs were supplied on the command 714 // line. Add an empty URL, which is treated as opening the users home 715 // page. 716 urls_to_open_.push_back(GURL()); 717 } 718 AppendURLsToBrowser(browser, urls_to_open_); 719 browser->window()->Show(); 720 } 721 722 if (succeeded) { 723 DCHECK(tab_loader_.get()); 724 // TabLoader deletes itself when done loading. 725 tab_loader_->StartLoading(); 726 tab_loader_ = NULL; 727 } 728 729 if (!synchronous_) { 730 // If we're not synchronous we need to delete ourself. 731 // NOTE: we must use DeleteLater here as most likely we're in a callback 732 // from the history service which doesn't deal well with deleting the 733 // object it is notifying. 734 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 735 736 // The delete may take a while and at this point we no longer care about 737 // if the browser is deleted. Don't listen to anything. This avoid a 738 // possible double delete too (if browser is closed before DeleteSoon() is 739 // processed). 740 registrar_.RemoveAll(); 741 } 742 743 #if defined(OS_CHROMEOS) 744 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 745 "SessionRestore-End", false); 746 #endif 747 return browser; 748 } 749 750 void OnGotSession(ScopedVector<SessionWindow> windows, 751 SessionID::id_type active_window_id) { 752 base::TimeDelta time_to_got_sessions = 753 base::TimeTicks::Now() - restore_started_; 754 UMA_HISTOGRAM_CUSTOM_TIMES( 755 "SessionRestore.TimeToGotSessions", 756 time_to_got_sessions, 757 base::TimeDelta::FromMilliseconds(10), 758 base::TimeDelta::FromSeconds(1000), 759 100); 760 #if defined(OS_CHROMEOS) 761 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 762 "SessionRestore-GotSession", false); 763 #endif 764 if (synchronous_) { 765 // See comment above windows_ as to why we don't process immediately. 766 windows_.swap(windows.get()); 767 active_window_id_ = active_window_id; 768 base::MessageLoop::current()->QuitNow(); 769 return; 770 } 771 772 ProcessSessionWindows(&windows.get(), active_window_id); 773 } 774 775 Browser* ProcessSessionWindows(std::vector<SessionWindow*>* windows, 776 SessionID::id_type active_window_id) { 777 VLOG(1) << "ProcessSessionWindows " << windows->size(); 778 base::TimeDelta time_to_process_sessions = 779 base::TimeTicks::Now() - restore_started_; 780 UMA_HISTOGRAM_CUSTOM_TIMES( 781 "SessionRestore.TimeToProcessSessions", 782 time_to_process_sessions, 783 base::TimeDelta::FromMilliseconds(10), 784 base::TimeDelta::FromSeconds(1000), 785 100); 786 787 if (windows->empty()) { 788 // Restore was unsuccessful. The DOM storage system can also delete its 789 // data, since no session restore will happen at a later point in time. 790 content::BrowserContext::GetDefaultStoragePartition(profile_)-> 791 GetDOMStorageContext()->StartScavengingUnusedSessionStorage(); 792 return FinishedTabCreation(false, false); 793 } 794 795 #if defined(OS_CHROMEOS) 796 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 797 "SessionRestore-CreatingTabs-Start", false); 798 #endif 799 StartTabCreation(); 800 801 // After the for loop this contains the last TABBED_BROWSER. Is null if no 802 // tabbed browsers exist. 803 Browser* last_browser = NULL; 804 bool has_tabbed_browser = false; 805 806 // After the for loop, this contains the browser to activate, if one of the 807 // windows has the same id as specified in active_window_id. 808 Browser* browser_to_activate = NULL; 809 #if defined(OS_WIN) 810 int selected_tab_to_activate = -1; 811 #endif 812 813 // Determine if there is a visible window. 814 bool has_visible_browser = false; 815 for (std::vector<SessionWindow*>::iterator i = windows->begin(); 816 i != windows->end(); ++i) { 817 if ((*i)->show_state != ui::SHOW_STATE_MINIMIZED) 818 has_visible_browser = true; 819 } 820 821 for (std::vector<SessionWindow*>::iterator i = windows->begin(); 822 i != windows->end(); ++i) { 823 Browser* browser = NULL; 824 if (!has_tabbed_browser && (*i)->type == Browser::TYPE_TABBED) 825 has_tabbed_browser = true; 826 if (i == windows->begin() && (*i)->type == Browser::TYPE_TABBED && 827 browser_ && browser_->is_type_tabbed() && 828 !browser_->profile()->IsOffTheRecord()) { 829 // The first set of tabs is added to the existing browser. 830 browser = browser_; 831 } else { 832 #if defined(OS_CHROMEOS) 833 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 834 "SessionRestore-CreateRestoredBrowser-Start", false); 835 #endif 836 // Show the first window if none are visible. 837 ui::WindowShowState show_state = (*i)->show_state; 838 if (!has_visible_browser) { 839 show_state = ui::SHOW_STATE_NORMAL; 840 has_visible_browser = true; 841 } 842 browser = NULL; 843 #if defined(OS_WIN) 844 if (win8::IsSingleWindowMetroMode()) { 845 // We don't want to add tabs to the off the record browser. 846 if (browser_ && !browser_->profile()->IsOffTheRecord()) { 847 browser = browser_; 848 } else { 849 browser = last_browser; 850 // last_browser should never be off the record either. 851 // We don't set browser higher above when browser_ is offtherecord, 852 // and CreateRestoredBrowser below, is never created offtherecord. 853 DCHECK(!browser || !browser->profile()->IsOffTheRecord()); 854 } 855 // Metro should only have tabbed browsers. 856 // It never creates any non-tabbed browser, and thus should never 857 // restore non-tabbed items... 858 DCHECK(!browser || browser->is_type_tabbed()); 859 DCHECK((*i)->type == Browser::TYPE_TABBED); 860 } 861 #endif 862 if (!browser) { 863 browser = CreateRestoredBrowser( 864 static_cast<Browser::Type>((*i)->type), 865 (*i)->bounds, 866 show_state, 867 (*i)->app_name); 868 } 869 #if defined(OS_CHROMEOS) 870 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 871 "SessionRestore-CreateRestoredBrowser-End", false); 872 #endif 873 } 874 if ((*i)->type == Browser::TYPE_TABBED) 875 last_browser = browser; 876 WebContents* active_tab = 877 browser->tab_strip_model()->GetActiveWebContents(); 878 int initial_tab_count = browser->tab_strip_model()->count(); 879 bool close_active_tab = clobber_existing_tab_ && 880 i == windows->begin() && 881 (*i)->type == Browser::TYPE_TABBED && 882 active_tab && browser == browser_ && 883 (*i)->tabs.size() > 0; 884 if (close_active_tab) 885 --initial_tab_count; 886 int selected_tab_index = 887 initial_tab_count > 0 ? browser->tab_strip_model()->active_index() 888 : std::max(0, 889 std::min((*i)->selected_tab_index, 890 static_cast<int>((*i)->tabs.size()) - 1)); 891 if ((*i)->window_id.id() == active_window_id) { 892 browser_to_activate = browser; 893 #if defined(OS_WIN) 894 selected_tab_to_activate = selected_tab_index; 895 #endif 896 } 897 RestoreTabsToBrowser(*(*i), browser, initial_tab_count, 898 selected_tab_index); 899 NotifySessionServiceOfRestoredTabs(browser, initial_tab_count); 900 // This needs to be done after restore because closing the last tab will 901 // close the whole window. 902 if (close_active_tab) 903 chrome::CloseWebContents(browser, active_tab, true); 904 #if defined(OS_WIN) 905 selected_tab_to_activate = -1; 906 #endif 907 } 908 909 if (browser_to_activate && browser_to_activate->is_type_tabbed()) 910 last_browser = browser_to_activate; 911 912 if (last_browser && !urls_to_open_.empty()) 913 AppendURLsToBrowser(last_browser, urls_to_open_); 914 #if defined(OS_CHROMEOS) 915 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 916 "SessionRestore-CreatingTabs-End", false); 917 #endif 918 if (browser_to_activate) { 919 browser_to_activate->window()->Activate(); 920 #if defined(OS_WIN) 921 // On Win8 Metro, we merge all browsers together, so if we need to 922 // activate one of the previously separated window, we need to activate 923 // the tab. Also, selected_tab_to_activate can be -1 if we clobbered the 924 // tab that would have been activated. 925 // In that case we'll leave activation to last tab. 926 // The only current usage of clobber is for crash recovery, so it's fine. 927 if (win8::IsSingleWindowMetroMode() && selected_tab_to_activate != -1) 928 ShowBrowser(browser_to_activate, selected_tab_to_activate); 929 #endif 930 } 931 932 // If last_browser is NULL and urls_to_open_ is non-empty, 933 // FinishedTabCreation will create a new TabbedBrowser and add the urls to 934 // it. 935 Browser* finished_browser = FinishedTabCreation(true, has_tabbed_browser); 936 if (finished_browser) 937 last_browser = finished_browser; 938 939 // sessionStorages needed for the session restore have now been recreated 940 // by RestoreTab. Now it's safe for the DOM storage system to start 941 // deleting leftover data. 942 content::BrowserContext::GetDefaultStoragePartition(profile_)-> 943 GetDOMStorageContext()->StartScavengingUnusedSessionStorage(); 944 return last_browser; 945 } 946 947 // Record an app launch event (if appropriate) for a tab which is about to 948 // be restored. Callers should ensure that selected_index is within the 949 // bounds of tab.navigations before calling. 950 void RecordAppLaunchForTab(Browser* browser, 951 const SessionTab& tab, 952 int selected_index) { 953 DCHECK(selected_index >= 0 && 954 selected_index < static_cast<int>(tab.navigations.size())); 955 GURL url = tab.navigations[selected_index].virtual_url(); 956 if (browser->profile()->GetExtensionService()) { 957 const extensions::Extension* extension = 958 browser->profile()->GetExtensionService()->GetInstalledApp(url); 959 if (extension) { 960 CoreAppLauncherHandler::RecordAppLaunchType( 961 extension_misc::APP_LAUNCH_SESSION_RESTORE, 962 extension->GetType()); 963 } 964 } 965 } 966 967 // Adds the tabs from |window| to |browser|. Normal tabs go after the existing 968 // tabs but pinned tabs will be pushed in front. 969 // If there are no existing tabs, the tab at |selected_tab_index| will be 970 // selected. Otherwise, the tab selection will remain untouched. 971 void RestoreTabsToBrowser(const SessionWindow& window, 972 Browser* browser, 973 int initial_tab_count, 974 int selected_tab_index) { 975 VLOG(1) << "RestoreTabsToBrowser " << window.tabs.size(); 976 DCHECK(!window.tabs.empty()); 977 if (initial_tab_count == 0) { 978 for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) { 979 const SessionTab& tab = *(window.tabs[i]); 980 // Loads are scheduled for each restored tab unless the tab is going to 981 // be selected as ShowBrowser() will load the selected tab. 982 if (i == selected_tab_index) { 983 ShowBrowser(browser, 984 browser->tab_strip_model()->GetIndexOfWebContents( 985 RestoreTab(tab, i, browser, false))); 986 tab_loader_->TabIsLoading( 987 &browser->tab_strip_model()->GetActiveWebContents()-> 988 GetController()); 989 } else { 990 RestoreTab(tab, i, browser, true); 991 } 992 } 993 } else { 994 // If the browser already has tabs, we want to restore the new ones after 995 // the existing ones. E.g. this happens in Win8 Metro where we merge 996 // windows or when launching a hosted app from the app launcher. 997 int tab_index_offset = initial_tab_count; 998 for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) { 999 const SessionTab& tab = *(window.tabs[i]); 1000 // Always schedule loads as we will not be calling ShowBrowser(). 1001 RestoreTab(tab, tab_index_offset + i, browser, true); 1002 } 1003 } 1004 } 1005 1006 // |tab_index| is ignored for pinned tabs which will always be pushed behind 1007 // the last existing pinned tab. 1008 // |schedule_load| will let |tab_loader_| know that it should schedule this 1009 // tab for loading. 1010 WebContents* RestoreTab(const SessionTab& tab, 1011 const int tab_index, 1012 Browser* browser, 1013 bool schedule_load) { 1014 // It's possible (particularly for foreign sessions) to receive a tab 1015 // without valid navigations. In that case, just skip it. 1016 // See crbug.com/154129. 1017 if (tab.navigations.empty()) 1018 return NULL; 1019 int selected_index = tab.current_navigation_index; 1020 selected_index = std::max( 1021 0, 1022 std::min(selected_index, 1023 static_cast<int>(tab.navigations.size() - 1))); 1024 1025 RecordAppLaunchForTab(browser, tab, selected_index); 1026 1027 // Associate sessionStorage (if any) to the restored tab. 1028 scoped_refptr<content::SessionStorageNamespace> session_storage_namespace; 1029 if (!tab.session_storage_persistent_id.empty()) { 1030 session_storage_namespace = 1031 content::BrowserContext::GetDefaultStoragePartition(profile_)-> 1032 GetDOMStorageContext()->RecreateSessionStorage( 1033 tab.session_storage_persistent_id); 1034 } 1035 1036 WebContents* web_contents = 1037 chrome::AddRestoredTab(browser, 1038 tab.navigations, 1039 tab_index, 1040 selected_index, 1041 tab.extension_app_id, 1042 false, // select 1043 tab.pinned, 1044 true, 1045 session_storage_namespace.get(), 1046 tab.user_agent_override); 1047 // Regression check: check that the tab didn't start loading right away. The 1048 // focused tab will be loaded by Browser, and TabLoader will load the rest. 1049 DCHECK(web_contents->GetController().NeedsReload()); 1050 1051 // Set up the file access rights for the selected navigation entry. 1052 const int id = web_contents->GetRenderProcessHost()->GetID(); 1053 const content::PageState& page_state = 1054 tab.navigations.at(selected_index).page_state(); 1055 const std::vector<base::FilePath>& file_paths = 1056 page_state.GetReferencedFiles(); 1057 for (std::vector<base::FilePath>::const_iterator file = file_paths.begin(); 1058 file != file_paths.end(); ++file) { 1059 content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(id, 1060 *file); 1061 } 1062 1063 if (schedule_load) 1064 tab_loader_->ScheduleLoad(&web_contents->GetController()); 1065 return web_contents; 1066 } 1067 1068 Browser* CreateRestoredBrowser(Browser::Type type, 1069 gfx::Rect bounds, 1070 ui::WindowShowState show_state, 1071 const std::string& app_name) { 1072 Browser::CreateParams params(type, profile_, host_desktop_type_); 1073 params.app_name = app_name; 1074 params.initial_bounds = bounds; 1075 params.initial_show_state = show_state; 1076 params.is_session_restore = true; 1077 return new Browser(params); 1078 } 1079 1080 void ShowBrowser(Browser* browser, int selected_tab_index) { 1081 DCHECK(browser); 1082 DCHECK(browser->tab_strip_model()->count()); 1083 browser->tab_strip_model()->ActivateTabAt(selected_tab_index, true); 1084 1085 if (browser_ == browser) 1086 return; 1087 1088 #if defined(USE_ASH) 1089 // Prevent the auto window management for this window on show. 1090 ash::wm::SetUserHasChangedWindowPositionOrSize( 1091 browser->window()->GetNativeWindow(), true); 1092 #endif 1093 browser->window()->Show(); 1094 #if defined(USE_ASH) 1095 ash::wm::SetUserHasChangedWindowPositionOrSize( 1096 browser->window()->GetNativeWindow(), false); 1097 #endif 1098 browser->set_is_session_restore(false); 1099 1100 // TODO(jcampan): http://crbug.com/8123 we should not need to set the 1101 // initial focus explicitly. 1102 browser->tab_strip_model()->GetActiveWebContents()-> 1103 GetView()->SetInitialFocus(); 1104 1105 if (!browser_shown_) { 1106 browser_shown_ = true; 1107 base::TimeDelta time_to_first_show = 1108 base::TimeTicks::Now() - restore_started_; 1109 UMA_HISTOGRAM_CUSTOM_TIMES( 1110 "SessionRestore.TimeToFirstShow", 1111 time_to_first_show, 1112 base::TimeDelta::FromMilliseconds(10), 1113 base::TimeDelta::FromSeconds(1000), 1114 100); 1115 } 1116 } 1117 1118 // Appends the urls in |urls| to |browser|. 1119 void AppendURLsToBrowser(Browser* browser, 1120 const std::vector<GURL>& urls) { 1121 for (size_t i = 0; i < urls.size(); ++i) { 1122 int add_types = TabStripModel::ADD_FORCE_INDEX; 1123 if (i == 0) 1124 add_types |= TabStripModel::ADD_ACTIVE; 1125 chrome::NavigateParams params(browser, urls[i], 1126 content::PAGE_TRANSITION_AUTO_TOPLEVEL); 1127 params.disposition = i == 0 ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB; 1128 params.tabstrip_add_types = add_types; 1129 chrome::Navigate(¶ms); 1130 } 1131 } 1132 1133 // Invokes TabRestored on the SessionService for all tabs in browser after 1134 // initial_count. 1135 void NotifySessionServiceOfRestoredTabs(Browser* browser, int initial_count) { 1136 SessionService* session_service = 1137 SessionServiceFactory::GetForProfile(profile_); 1138 if (!session_service) 1139 return; 1140 TabStripModel* tab_strip = browser->tab_strip_model(); 1141 for (int i = initial_count; i < tab_strip->count(); ++i) 1142 session_service->TabRestored(tab_strip->GetWebContentsAt(i), 1143 tab_strip->IsTabPinned(i)); 1144 } 1145 1146 // The profile to create the sessions for. 1147 Profile* profile_; 1148 1149 // The first browser to restore to, may be null. 1150 Browser* browser_; 1151 1152 // The desktop on which all new browsers should be created (browser_, if it is 1153 // not NULL, must be of this desktop type as well). 1154 chrome::HostDesktopType host_desktop_type_; 1155 1156 // Whether or not restore is synchronous. 1157 const bool synchronous_; 1158 1159 // See description of CLOBBER_CURRENT_TAB. 1160 const bool clobber_existing_tab_; 1161 1162 // If true and there is an error or there are no windows to restore, we 1163 // create a tabbed browser anyway. This is used on startup to make sure at 1164 // at least one window is created. 1165 const bool always_create_tabbed_browser_; 1166 1167 // Set of URLs to open in addition to those restored from the session. 1168 std::vector<GURL> urls_to_open_; 1169 1170 // Used to get the session. 1171 CancelableTaskTracker cancelable_task_tracker_; 1172 1173 // Responsible for loading the tabs. 1174 scoped_refptr<TabLoader> tab_loader_; 1175 1176 // When synchronous we run a nested message loop. To avoid creating windows 1177 // from the nested message loop (which can make exiting the nested message 1178 // loop take a while) we cache the SessionWindows here and create the actual 1179 // windows when the nested message loop exits. 1180 std::vector<SessionWindow*> windows_; 1181 SessionID::id_type active_window_id_; 1182 1183 content::NotificationRegistrar registrar_; 1184 1185 // The time we started the restore. 1186 base::TimeTicks restore_started_; 1187 1188 // Set to true after the first browser is shown. 1189 bool browser_shown_; 1190 1191 DISALLOW_COPY_AND_ASSIGN(SessionRestoreImpl); 1192 }; 1193 1194 } // namespace 1195 1196 // SessionRestore ------------------------------------------------------------- 1197 1198 // static 1199 Browser* SessionRestore::RestoreSession( 1200 Profile* profile, 1201 Browser* browser, 1202 chrome::HostDesktopType host_desktop_type, 1203 uint32 behavior, 1204 const std::vector<GURL>& urls_to_open) { 1205 #if defined(OS_CHROMEOS) 1206 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 1207 "SessionRestore-Start", false); 1208 #endif 1209 DCHECK(profile); 1210 // Always restore from the original profile (incognito profiles have no 1211 // session service). 1212 profile = profile->GetOriginalProfile(); 1213 if (!SessionServiceFactory::GetForProfile(profile)) { 1214 NOTREACHED(); 1215 return NULL; 1216 } 1217 profile->set_restored_last_session(true); 1218 // SessionRestoreImpl takes care of deleting itself when done. 1219 SessionRestoreImpl* restorer = new SessionRestoreImpl( 1220 profile, browser, host_desktop_type, (behavior & SYNCHRONOUS) != 0, 1221 (behavior & CLOBBER_CURRENT_TAB) != 0, 1222 (behavior & ALWAYS_CREATE_TABBED_BROWSER) != 0, 1223 urls_to_open); 1224 return restorer->Restore(); 1225 } 1226 1227 // static 1228 std::vector<Browser*> SessionRestore::RestoreForeignSessionWindows( 1229 Profile* profile, 1230 chrome::HostDesktopType host_desktop_type, 1231 std::vector<const SessionWindow*>::const_iterator begin, 1232 std::vector<const SessionWindow*>::const_iterator end) { 1233 std::vector<GURL> gurls; 1234 SessionRestoreImpl restorer(profile, 1235 static_cast<Browser*>(NULL), host_desktop_type, true, false, true, gurls); 1236 return restorer.RestoreForeignSession(begin, end); 1237 } 1238 1239 // static 1240 WebContents* SessionRestore::RestoreForeignSessionTab( 1241 content::WebContents* source_web_contents, 1242 const SessionTab& tab, 1243 WindowOpenDisposition disposition) { 1244 Browser* browser = chrome::FindBrowserWithWebContents(source_web_contents); 1245 Profile* profile = browser->profile(); 1246 std::vector<GURL> gurls; 1247 SessionRestoreImpl restorer(profile, browser, browser->host_desktop_type(), 1248 true, false, false, gurls); 1249 return restorer.RestoreForeignTab(tab, disposition); 1250 } 1251 1252 // static 1253 bool SessionRestore::IsRestoring(const Profile* profile) { 1254 if (active_session_restorers == NULL) 1255 return false; 1256 for (std::set<SessionRestoreImpl*>::const_iterator it = 1257 active_session_restorers->begin(); 1258 it != active_session_restorers->end(); ++it) { 1259 if ((*it)->profile() == profile) 1260 return true; 1261 } 1262 return false; 1263 } 1264 1265 // static 1266 bool SessionRestore::IsRestoringSynchronously() { 1267 if (!active_session_restorers) 1268 return false; 1269 for (std::set<SessionRestoreImpl*>::const_iterator it = 1270 active_session_restorers->begin(); 1271 it != active_session_restorers->end(); ++it) { 1272 if ((*it)->synchronous()) 1273 return true; 1274 } 1275 return false; 1276 } 1277