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