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