Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: chrome/browser/sessions/in_memory_tab_restore_service.cc

Issue 10989027: Split TabRestoreService into InMemoryTRS and PersistentTRS (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix build on Mac (not tested locally) Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sessions/tab_restore_service.h" 5 #include "chrome/browser/sessions/in_memory_tab_restore_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <iterator> 8 #include <iterator>
9 #include <map>
10 9
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/callback.h"
14 #include "base/memory/scoped_vector.h"
15 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
16 #include "base/stl_util.h" 11 #include "base/stl_util.h"
17 #include "chrome/browser/extensions/extension_service.h" 12 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/tab_helper.h" 13 #include "chrome/browser/extensions/tab_helper.h"
19 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/sessions/session_command.h"
21 #include "chrome/browser/sessions/session_service.h"
22 #include "chrome/browser/sessions/session_service_factory.h"
23 #include "chrome/browser/sessions/session_types.h" 15 #include "chrome/browser/sessions/session_types.h"
24 #include "chrome/browser/sessions/tab_restore_service_delegate.h" 16 #include "chrome/browser/sessions/tab_restore_service_delegate.h"
25 #include "chrome/browser/sessions/tab_restore_service_observer.h" 17 #include "chrome/browser/sessions/tab_restore_service_observer.h"
26 #include "chrome/browser/ui/tab_contents/tab_contents.h" 18 #include "chrome/browser/ui/tab_contents/tab_contents.h"
27 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" 19 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
28 #include "chrome/common/extensions/extension.h" 20 #include "chrome/common/extensions/extension.h"
29 #include "chrome/common/extensions/extension_constants.h" 21 #include "chrome/common/extensions/extension_constants.h"
30 #include "chrome/common/url_constants.h" 22 #include "chrome/common/url_constants.h"
31 #include "content/public/browser/navigation_controller.h" 23 #include "content/public/browser/navigation_controller.h"
32 #include "content/public/browser/navigation_entry.h" 24 #include "content/public/browser/navigation_entry.h"
33 #include "content/public/browser/web_contents.h" 25 #include "content/public/browser/web_contents.h"
26 #include "content/public/browser/session_storage_namespace.h"
34 27
35 using base::Time;
36 using content::NavigationController; 28 using content::NavigationController;
37 using content::NavigationEntry; 29 using content::NavigationEntry;
38 using content::WebContents; 30 using content::WebContents;
39 31
40 // TimeFactory-----------------------------------------------------------------
41
42 TabRestoreService::TimeFactory::~TimeFactory() {}
43
44 // Entry ----------------------------------------------------------------------
45
46 // ID of the next Entry.
47 static SessionID::id_type next_entry_id = 1;
48
49 TabRestoreService::Entry::Entry()
50 : id(next_entry_id++),
51 type(TAB),
52 from_last_session(false) {}
53
54 TabRestoreService::Entry::Entry(Type type)
55 : id(next_entry_id++),
56 type(type),
57 from_last_session(false) {}
58
59 TabRestoreService::Entry::~Entry() {}
60
61 // TabRestoreService ----------------------------------------------------------
62
63 // static
64 const size_t TabRestoreService::kMaxEntries = 25;
65
66 // Identifier for commands written to file.
67 // The ordering in the file is as follows:
68 // . When the user closes a tab a command of type
69 // kCommandSelectedNavigationInTab is written identifying the tab and
70 // the selected index, then a kCommandPinnedState command if the tab was
71 // pinned and kCommandSetExtensionAppID if the tab has an app id and
72 // the user agent override if it was using one. This is
73 // followed by any number of kCommandUpdateTabNavigation commands (1 per
74 // navigation entry).
75 // . When the user closes a window a kCommandSelectedNavigationInTab command
76 // is written out and followed by n tab closed sequences (as previoulsy
77 // described).
78 // . When the user restores an entry a command of type kCommandRestoredEntry
79 // is written.
80 static const SessionCommand::id_type kCommandUpdateTabNavigation = 1;
81 static const SessionCommand::id_type kCommandRestoredEntry = 2;
82 static const SessionCommand::id_type kCommandWindow = 3;
83 static const SessionCommand::id_type kCommandSelectedNavigationInTab = 4;
84 static const SessionCommand::id_type kCommandPinnedState = 5;
85 static const SessionCommand::id_type kCommandSetExtensionAppID = 6;
86 static const SessionCommand::id_type kCommandSetWindowAppName = 7;
87 static const SessionCommand::id_type kCommandSetTabUserAgentOverride = 8;
88
89 // Number of entries (not commands) before we clobber the file and write
90 // everything.
91 static const int kEntriesPerReset = 40;
92
93 namespace { 32 namespace {
94 33
95 // Payload structures.
96
97 typedef int32 RestoredEntryPayload;
98
99 // Payload used for the start of a window close. This is the old struct that is
100 // used for backwards compat when it comes to reading the session files. This
101 // struct must be POD, because we memset the contents.
102 struct WindowPayload {
103 SessionID::id_type window_id;
104 int32 selected_tab_index;
105 int32 num_tabs;
106 };
107
108 // Payload used for the start of a tab close. This is the old struct that is
109 // used for backwards compat when it comes to reading the session files.
110 struct SelectedNavigationInTabPayload {
111 SessionID::id_type id;
112 int32 index;
113 };
114
115 // Payload used for the start of a window close. This struct must be POD,
116 // because we memset the contents.
117 struct WindowPayload2 : WindowPayload {
118 int64 timestamp;
119 };
120
121 // Payload used for the start of a tab close.
122 struct SelectedNavigationInTabPayload2 : SelectedNavigationInTabPayload {
123 int64 timestamp;
124 };
125
126 // Only written if the tab is pinned.
127 typedef bool PinnedStatePayload;
128
129 typedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry;
130
131 // If |id_to_entry| contains an entry for |id| the corresponding entry is
132 // deleted and removed from both |id_to_entry| and |entries|. This is used
133 // when creating entries from the backend file.
134 void RemoveEntryByID(SessionID::id_type id,
135 IDToEntry* id_to_entry,
136 std::vector<TabRestoreService::Entry*>* entries) {
137 // Look for the entry in the map. If it is present, erase it from both
138 // collections and return.
139 IDToEntry::iterator i = id_to_entry->find(id);
140 if (i != id_to_entry->end()) {
141 entries->erase(std::find(entries->begin(), entries->end(), i->second));
142 delete i->second;
143 id_to_entry->erase(i);
144 return;
145 }
146
147 // Otherwise, loop over all items in the map and see if any of the Windows
148 // have Tabs with the |id|.
149 for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end();
150 ++i) {
151 if (i->second->type == TabRestoreService::WINDOW) {
152 TabRestoreService::Window* window =
153 static_cast<TabRestoreService::Window*>(i->second);
154 std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin();
155 for ( ; j != window->tabs.end(); ++j) {
156 // If the ID matches one of this window's tabs, remove it from the list.
157 if ((*j).id == id) {
158 window->tabs.erase(j);
159 return;
160 }
161 }
162 }
163 }
164 }
165
166 void RecordAppLaunch(Profile* profile, const TabRestoreService::Tab& tab) { 34 void RecordAppLaunch(Profile* profile, const TabRestoreService::Tab& tab) {
35 #if !defined(OS_ANDROID)
167 GURL url = tab.navigations.at(tab.current_navigation_index).virtual_url(); 36 GURL url = tab.navigations.at(tab.current_navigation_index).virtual_url();
168 DCHECK(profile->GetExtensionService()); 37 DCHECK(profile->GetExtensionService());
169 if (!profile->GetExtensionService()->IsInstalledApp(url)) 38 if (!profile->GetExtensionService()->IsInstalledApp(url))
170 return; 39 return;
171 40
172 AppLauncherHandler::RecordAppLaunchType( 41 AppLauncherHandler::RecordAppLaunchType(
173 extension_misc::APP_LAUNCH_NTP_RECENTLY_CLOSED); 42 extension_misc::APP_LAUNCH_NTP_RECENTLY_CLOSED);
43 #endif // !defined(OS_ANDROID)
174 } 44 }
175 45
176 } // namespace 46 } // namespace
177 47
178 TabRestoreService::Tab::Tab() 48 InMemoryTabRestoreService::InMemoryTabRestoreService(
179 : Entry(TAB), 49 Profile* profile,
180 current_navigation_index(-1),
181 browser_id(0),
182 tabstrip_index(-1),
183 pinned(false) {
184 }
185
186 TabRestoreService::Tab::~Tab() {
187 }
188
189 TabRestoreService::Window::Window() : Entry(WINDOW), selected_tab_index(-1) {
190 }
191
192 TabRestoreService::Window::~Window() {
193 }
194
195 TabRestoreService::TabRestoreService(Profile* profile,
196 TabRestoreService::TimeFactory* time_factory) 50 TabRestoreService::TimeFactory* time_factory)
197 : BaseSessionService(BaseSessionService::TAB_RESTORE, profile, 51 : profile_(profile),
198 FilePath()),
199 load_state_(NOT_LOADED),
200 restoring_(false), 52 restoring_(false),
201 entries_to_write_(0),
202 entries_written_(0),
203 time_factory_(time_factory) { 53 time_factory_(time_factory) {
204 } 54 }
205 55
206 TabRestoreService::~TabRestoreService() { 56 InMemoryTabRestoreService::~InMemoryTabRestoreService() {
207 FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, 57 FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
208 TabRestoreServiceDestroyed(this)); 58 TabRestoreServiceDestroyed(this));
209 STLDeleteElements(&entries_); 59 STLDeleteElements(&entries_);
210 STLDeleteElements(&staging_entries_);
211 time_factory_ = NULL;
212 } 60 }
213 61
214 void TabRestoreService::AddObserver(TabRestoreServiceObserver* observer) { 62 void InMemoryTabRestoreService::AddObserver(
63 TabRestoreServiceObserver* observer) {
215 observer_list_.AddObserver(observer); 64 observer_list_.AddObserver(observer);
216 } 65 }
217 66
218 void TabRestoreService::RemoveObserver(TabRestoreServiceObserver* observer) { 67 void InMemoryTabRestoreService::RemoveObserver(
68 TabRestoreServiceObserver* observer) {
219 observer_list_.RemoveObserver(observer); 69 observer_list_.RemoveObserver(observer);
220 } 70 }
221 71
222 void TabRestoreService::CreateHistoricalTab(content::WebContents* contents, 72 void InMemoryTabRestoreService::CreateHistoricalTab(
223 int index) { 73 content::WebContents* contents,
74 int index) {
224 if (restoring_) 75 if (restoring_)
225 return; 76 return;
226 77
227 TabRestoreServiceDelegate* delegate = 78 TabRestoreServiceDelegate* delegate =
228 TabRestoreServiceDelegate::FindDelegateForWebContents(contents); 79 TabRestoreServiceDelegate::FindDelegateForWebContents(contents);
229 if (closing_delegates_.find(delegate) != closing_delegates_.end()) 80 if (closing_delegates_.find(delegate) != closing_delegates_.end())
230 return; 81 return;
231 82
232 scoped_ptr<Tab> local_tab(new Tab()); 83 scoped_ptr<Tab> local_tab(new Tab());
233 PopulateTab(local_tab.get(), index, delegate, &contents->GetController()); 84 PopulateTab(local_tab.get(), index, delegate, &contents->GetController());
234 if (local_tab->navigations.empty()) 85 if (local_tab->navigations.empty())
235 return; 86 return;
236 87
237 AddEntry(local_tab.release(), true, true); 88 AddEntry(local_tab.release(), true, true);
238 } 89 }
239 90
240 void TabRestoreService::BrowserClosing(TabRestoreServiceDelegate* delegate) { 91 void InMemoryTabRestoreService::BrowserClosing(
92 TabRestoreServiceDelegate* delegate) {
241 closing_delegates_.insert(delegate); 93 closing_delegates_.insert(delegate);
242 94
243 scoped_ptr<Window> window(new Window()); 95 scoped_ptr<Window> window(new Window());
244 window->selected_tab_index = delegate->GetSelectedIndex(); 96 window->selected_tab_index = delegate->GetSelectedIndex();
245 window->timestamp = TimeNow(); 97 window->timestamp = TimeNow();
246 window->app_name = delegate->GetAppName(); 98 window->app_name = delegate->GetAppName();
247 99
248 // Don't use std::vector::resize() because it will push copies of an empty tab 100 // Don't use std::vector::resize() because it will push copies of an empty tab
249 // into the vector, which will give all tabs in a window the same ID. 101 // into the vector, which will give all tabs in a window the same ID.
250 for (int i = 0; i < delegate->GetTabCount(); ++i) { 102 for (int i = 0; i < delegate->GetTabCount(); ++i) {
(...skipping 18 matching lines...) Expand all
269 // the stack. 121 // the stack.
270 AddEntry(new Tab(window->tabs[0]), true, true); 122 AddEntry(new Tab(window->tabs[0]), true, true);
271 } else if (!window->tabs.empty()) { 123 } else if (!window->tabs.empty()) {
272 window->selected_tab_index = 124 window->selected_tab_index =
273 std::min(static_cast<int>(window->tabs.size() - 1), 125 std::min(static_cast<int>(window->tabs.size() - 1),
274 window->selected_tab_index); 126 window->selected_tab_index);
275 AddEntry(window.release(), true, true); 127 AddEntry(window.release(), true, true);
276 } 128 }
277 } 129 }
278 130
279 void TabRestoreService::BrowserClosed(TabRestoreServiceDelegate* delegate) { 131 void InMemoryTabRestoreService::BrowserClosed(
132 TabRestoreServiceDelegate* delegate) {
280 closing_delegates_.erase(delegate); 133 closing_delegates_.erase(delegate);
281 } 134 }
282 135
283 void TabRestoreService::ClearEntries() { 136 void InMemoryTabRestoreService::ClearEntries() {
284 // Mark all the tabs as closed so that we don't attempt to restore them. 137 OnClearEntries();
285 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i)
286 ScheduleCommand(CreateRestoredEntryCommand((*i)->id));
287
288 entries_to_write_ = 0;
289
290 // Schedule a pending reset so that we nuke the file on next write.
291 set_pending_reset(true);
292
293 // Schedule a command, otherwise if there are no pending commands Save does
294 // nothing.
295 ScheduleCommand(CreateRestoredEntryCommand(1));
296
297 STLDeleteElements(&entries_); 138 STLDeleteElements(&entries_);
298 NotifyTabsChanged(); 139 NotifyTabsChanged();
299 } 140 }
300 141
301 const TabRestoreService::Entries& TabRestoreService::entries() const { 142 const TabRestoreService::Entries& InMemoryTabRestoreService::entries() const {
302 return entries_; 143 return entries_;
303 } 144 }
304 145
305 void TabRestoreService::RestoreMostRecentEntry( 146 void InMemoryTabRestoreService::RestoreMostRecentEntry(
306 TabRestoreServiceDelegate* delegate) { 147 TabRestoreServiceDelegate* delegate) {
307 if (entries_.empty()) 148 if (entries_.empty())
308 return; 149 return;
309 150
310 RestoreEntryById(delegate, entries_.front()->id, UNKNOWN); 151 RestoreEntryById(delegate, entries_.front()->id, UNKNOWN);
311 } 152 }
312 153
313 TabRestoreService::Tab* TabRestoreService::RemoveTabEntryById( 154 TabRestoreService::Tab* InMemoryTabRestoreService::RemoveTabEntryById(
314 SessionID::id_type id) { 155 SessionID::id_type id) {
315 Entries::iterator i = GetEntryIteratorById(id); 156 Entries::iterator i = GetEntryIteratorById(id);
316 if (i == entries_.end()) 157 if (i == entries_.end())
317 return NULL; 158 return NULL;
318 159
319 Entry* entry = *i; 160 Entry* entry = *i;
320 if (entry->type != TAB) 161 if (entry->type != TAB)
321 return NULL; 162 return NULL;
322 163
323 Tab* tab = static_cast<Tab*>(entry); 164 Tab* tab = static_cast<Tab*>(entry);
324 entries_.erase(i); 165 entries_.erase(i);
325 return tab; 166 return tab;
326 } 167 }
327 168
328 void TabRestoreService::RestoreEntryById(TabRestoreServiceDelegate* delegate, 169 void InMemoryTabRestoreService::RestoreEntryById(
329 SessionID::id_type id, 170 TabRestoreServiceDelegate* delegate,
330 WindowOpenDisposition disposition) { 171 SessionID::id_type id,
331 Entries::iterator i = GetEntryIteratorById(id); 172 WindowOpenDisposition disposition) {
332 if (i == entries_.end()) { 173 Entries::iterator entry_iterator = GetEntryIteratorById(id);
174 if (entry_iterator == entries_.end())
333 // Don't hoark here, we allow an invalid id. 175 // Don't hoark here, we allow an invalid id.
334 return; 176 return;
335 }
336 177
337 size_t index = 0; 178 OnRestoreEntryById(id, entry_iterator);
338 for (Entries::iterator j = entries_.begin(); j != i && j != entries_.end();
339 ++j, ++index) {}
340 if (static_cast<int>(index) < entries_to_write_)
341 entries_to_write_--;
342
343 ScheduleCommand(CreateRestoredEntryCommand(id));
344
345 restoring_ = true; 179 restoring_ = true;
346 Entry* entry = *i; 180 Entry* entry = *entry_iterator;
347 181
348 // If the entry's ID does not match the ID that is being restored, then the 182 // If the entry's ID does not match the ID that is being restored, then the
349 // entry is a window from which a single tab will be restored. 183 // entry is a window from which a single tab will be restored.
350 bool restoring_tab_in_window = entry->id != id; 184 bool restoring_tab_in_window = entry->id != id;
351 185
352 if (!restoring_tab_in_window) { 186 if (!restoring_tab_in_window) {
353 entries_.erase(i); 187 entries_.erase(entry_iterator);
354 i = entries_.end(); 188 entry_iterator = entries_.end();
355 } 189 }
356 190
357 // |delegate| will be NULL in cases where one isn't already available (eg, 191 // |delegate| will be NULL in cases where one isn't already available (eg,
358 // when invoked on Mac OS X with no windows open). In this case, create a 192 // when invoked on Mac OS X with no windows open). In this case, create a
359 // new browser into which we restore the tabs. 193 // new browser into which we restore the tabs.
360 if (entry->type == TAB) { 194 if (entry->type == TAB) {
361 Tab* tab = static_cast<Tab*>(entry); 195 Tab* tab = static_cast<Tab*>(entry);
362 delegate = RestoreTab(*tab, delegate, disposition); 196 delegate = RestoreTab(*tab, delegate, disposition);
363 delegate->ShowBrowserWindow(); 197 delegate->ShowBrowserWindow();
364 } else if (entry->type == WINDOW) { 198 } else if (entry->type == WINDOW) {
365 TabRestoreServiceDelegate* current_delegate = delegate; 199 TabRestoreServiceDelegate* current_delegate = delegate;
366 Window* window = static_cast<Window*>(entry); 200 Window* window = static_cast<Window*>(entry);
367 201
368 // When restoring a window, either the entire window can be restored, or a 202 // When restoring a window, either the entire window can be restored, or a
369 // single tab within it. If the entry's ID matches the one to restore, then 203 // single tab within it. If the entry's ID matches the one to restore, then
370 // the entire window will be restored. 204 // the entire window will be restored.
371 if (!restoring_tab_in_window) { 205 if (!restoring_tab_in_window) {
372 delegate = TabRestoreServiceDelegate::Create(profile(), window->app_name); 206 delegate = TabRestoreServiceDelegate::Create(profile_, window->app_name);
373 for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) { 207 for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) {
374 const Tab& tab = window->tabs[tab_i]; 208 const Tab& tab = window->tabs[tab_i];
375 WebContents* restored_tab = 209 WebContents* restored_tab =
376 delegate->AddRestoredTab(tab.navigations, delegate->GetTabCount(), 210 delegate->AddRestoredTab(tab.navigations, delegate->GetTabCount(),
377 tab.current_navigation_index, 211 tab.current_navigation_index,
378 tab.extension_app_id, 212 tab.extension_app_id,
379 static_cast<int>(tab_i) == 213 static_cast<int>(tab_i) ==
380 window->selected_tab_index, 214 window->selected_tab_index,
381 tab.pinned, tab.from_last_session, 215 tab.pinned, tab.from_last_session,
382 tab.session_storage_namespace, 216 tab.session_storage_namespace,
383 tab.user_agent_override); 217 tab.user_agent_override);
384 if (restored_tab) { 218 if (restored_tab) {
385 restored_tab->GetController().LoadIfNecessary(); 219 restored_tab->GetController().LoadIfNecessary();
386 RecordAppLaunch(profile(), tab); 220 RecordAppLaunch(profile_, tab);
387 } 221 }
388 } 222 }
389 // All the window's tabs had the same former browser_id. 223 // All the window's tabs had the same former browser_id.
390 if (window->tabs[0].has_browser()) { 224 if (window->tabs[0].has_browser()) {
391 UpdateTabBrowserIDs(window->tabs[0].browser_id, 225 UpdateTabBrowserIDs(window->tabs[0].browser_id,
392 delegate->GetSessionID().id()); 226 delegate->GetSessionID().id());
393 } 227 }
394 } else { 228 } else {
395 // Restore a single tab from the window. Find the tab that matches the ID 229 // Restore a single tab from the window. Find the tab that matches the ID
396 // in the window and restore it. 230 // in the window and restore it.
397 for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); 231 for (std::vector<Tab>::iterator tab_i = window->tabs.begin();
398 tab_i != window->tabs.end(); ++tab_i) { 232 tab_i != window->tabs.end(); ++tab_i) {
399 const Tab& tab = *tab_i; 233 const Tab& tab = *tab_i;
400 if (tab.id == id) { 234 if (tab.id == id) {
401 delegate = RestoreTab(tab, delegate, disposition); 235 delegate = RestoreTab(tab, delegate, disposition);
402 window->tabs.erase(tab_i); 236 window->tabs.erase(tab_i);
403 // If restoring the tab leaves the window with nothing else, delete it 237 // If restoring the tab leaves the window with nothing else, delete it
404 // as well. 238 // as well.
405 if (!window->tabs.size()) { 239 if (!window->tabs.size()) {
406 entries_.erase(i); 240 entries_.erase(entry_iterator);
407 delete entry; 241 delete entry;
408 } else { 242 } else {
409 // Update the browser ID of the rest of the tabs in the window so if 243 // Update the browser ID of the rest of the tabs in the window so if
410 // any one is restored, it goes into the same window as the tab 244 // any one is restored, it goes into the same window as the tab
411 // being restored now. 245 // being restored now.
412 UpdateTabBrowserIDs(tab.browser_id, 246 UpdateTabBrowserIDs(tab.browser_id,
413 delegate->GetSessionID().id()); 247 delegate->GetSessionID().id());
414 for (std::vector<Tab>::iterator tab_j = window->tabs.begin(); 248 for (std::vector<Tab>::iterator tab_j = window->tabs.begin();
415 tab_j != window->tabs.end(); ++tab_j) { 249 tab_j != window->tabs.end(); ++tab_j) {
416 (*tab_j).browser_id = delegate->GetSessionID().id(); 250 (*tab_j).browser_id = delegate->GetSessionID().id();
(...skipping 14 matching lines...) Expand all
431 } 265 }
432 266
433 if (!restoring_tab_in_window) { 267 if (!restoring_tab_in_window) {
434 delete entry; 268 delete entry;
435 } 269 }
436 270
437 restoring_ = false; 271 restoring_ = false;
438 NotifyTabsChanged(); 272 NotifyTabsChanged();
439 } 273 }
440 274
441 void TabRestoreService::LoadTabsFromLastSession() { 275 void InMemoryTabRestoreService::LoadTabsFromLastSession() {
442 if (load_state_ != NOT_LOADED || entries_.size() == kMaxEntries) 276 NOTIMPLEMENTED();
443 return;
444
445 #if !defined(ENABLE_SESSION_SERVICE)
446 // If sessions are not stored in the SessionService, default to
447 // |LOADED_LAST_SESSION| state.
448 load_state_ = LOADING | LOADED_LAST_SESSION;
449 #else
450 load_state_ = LOADING;
451
452 SessionService* session_service =
453 SessionServiceFactory::GetForProfile(profile());
454 Profile::ExitType exit_type = profile()->GetLastSessionExitType();
455 if (!profile()->restored_last_session() && session_service &&
456 (exit_type == Profile::EXIT_CRASHED ||
457 exit_type == Profile::EXIT_SESSION_ENDED)) {
458 // The previous session crashed and wasn't restored, or was a forced
459 // shutdown. Both of which won't have notified us of the browser close so
460 // that we need to load the windows from session service (which will have
461 // saved them).
462 session_service->GetLastSession(
463 &crash_consumer_,
464 base::Bind(&TabRestoreService::OnGotPreviousSession,
465 base::Unretained(this)));
466 } else {
467 load_state_ |= LOADED_LAST_SESSION;
468 }
469 #endif
470
471 // Request the tabs closed in the last session. If the last session crashed,
472 // this won't contain the tabs/window that were open at the point of the
473 // crash (the call to GetLastSession above requests those).
474 ScheduleGetLastSessionCommands(
475 new InternalGetCommandsRequest(
476 base::Bind(&TabRestoreService::OnGotLastSessionCommands,
477 base::Unretained(this))),
478 &load_consumer_);
479 } 277 }
480 278
481 bool TabRestoreService::IsLoaded() const { 279 bool InMemoryTabRestoreService::IsLoaded() const {
482 return !(load_state_ & (NOT_LOADED | LOADING)); 280 NOTIMPLEMENTED();
281 return false;
483 } 282 }
484 283
485 void TabRestoreService::Shutdown() { 284 void InMemoryTabRestoreService::DeleteLastSession() {
486 if (backend()) 285 NOTIMPLEMENTED();
487 Save();
488 } 286 }
489 287
490 void TabRestoreService::Save() { 288 void InMemoryTabRestoreService::Shutdown() {}
491 int to_write_count = std::min(entries_to_write_,
492 static_cast<int>(entries_.size()));
493 entries_to_write_ = 0;
494 if (entries_written_ + to_write_count > kEntriesPerReset) {
495 to_write_count = entries_.size();
496 set_pending_reset(true);
497 }
498 if (to_write_count) {
499 // Write the to_write_count most recently added entries out. The most
500 // recently added entry is at the front, so we use a reverse iterator to
501 // write in the order the entries were added.
502 Entries::reverse_iterator i = entries_.rbegin();
503 DCHECK(static_cast<size_t>(to_write_count) <= entries_.size());
504 std::advance(i, entries_.size() - static_cast<int>(to_write_count));
505 for (; i != entries_.rend(); ++i) {
506 Entry* entry = *i;
507 if (entry->type == TAB) {
508 Tab* tab = static_cast<Tab*>(entry);
509 int selected_index = GetSelectedNavigationIndexToPersist(*tab);
510 if (selected_index != -1)
511 ScheduleCommandsForTab(*tab, selected_index);
512 } else {
513 ScheduleCommandsForWindow(*static_cast<Window*>(entry));
514 }
515 entries_written_++;
516 }
517 }
518 if (pending_reset())
519 entries_written_ = 0;
520 BaseSessionService::Save();
521 }
522 289
523 void TabRestoreService::PopulateTab(Tab* tab, 290 void InMemoryTabRestoreService::NotifyTabsChanged() {
524 int index,
525 TabRestoreServiceDelegate* delegate,
526 NavigationController* controller) {
527 const int pending_index = controller->GetPendingEntryIndex();
528 int entry_count = controller->GetEntryCount();
529 if (entry_count == 0 && pending_index == 0)
530 entry_count++;
531 tab->navigations.resize(static_cast<int>(entry_count));
532 for (int i = 0; i < entry_count; ++i) {
533 NavigationEntry* entry = (i == pending_index) ?
534 controller->GetPendingEntry() : controller->GetEntryAtIndex(i);
535 tab->navigations[i] =
536 TabNavigation::FromNavigationEntry(i, *entry);
537 }
538 tab->timestamp = TimeNow();
539 tab->current_navigation_index = controller->GetCurrentEntryIndex();
540 if (tab->current_navigation_index == -1 && entry_count > 0)
541 tab->current_navigation_index = 0;
542 tab->tabstrip_index = index;
543
544 TabContents* tab_contents =
545 TabContents::FromWebContents(controller->GetWebContents());
546 // tab_contents is NULL in some browser tests.
547 if (tab_contents) {
548 const extensions::Extension* extension =
549 extensions::TabHelper::FromWebContents(controller->GetWebContents())->
550 extension_app();
551 if (extension)
552 tab->extension_app_id = extension->id();
553 }
554
555 tab->user_agent_override =
556 controller->GetWebContents()->GetUserAgentOverride();
557
558 // TODO(ajwong): This does not correctly handle storage for isolated apps.
559 tab->session_storage_namespace =
560 controller->GetDefaultSessionStorageNamespace();
561
562 // Delegate may be NULL during unit tests.
563 if (delegate) {
564 tab->browser_id = delegate->GetSessionID().id();
565 tab->pinned = delegate->IsTabPinned(tab->tabstrip_index);
566 }
567 }
568
569 void TabRestoreService::NotifyTabsChanged() {
570 FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, 291 FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
571 TabRestoreServiceChanged(this)); 292 TabRestoreServiceChanged(this));
572 } 293 }
573 294
574 void TabRestoreService::AddEntry(Entry* entry, bool notify, bool to_front) { 295 void InMemoryTabRestoreService::AddEntry(Entry* entry,
296 bool notify,
297 bool to_front) {
575 if (!FilterEntry(entry) || (entries_.size() >= kMaxEntries && !to_front)) { 298 if (!FilterEntry(entry) || (entries_.size() >= kMaxEntries && !to_front)) {
576 delete entry; 299 delete entry;
577 return; 300 return;
578 } 301 }
579 302
580 if (to_front) 303 if (to_front)
581 entries_.push_front(entry); 304 entries_.push_front(entry);
582 else 305 else
583 entries_.push_back(entry); 306 entries_.push_back(entry);
584 307
585 PruneEntries(); 308 PruneEntries();
586 309
587 if (notify) 310 if (notify)
588 NotifyTabsChanged(); 311 NotifyTabsChanged();
589 312
590 // Start the save timer, when it fires we'll generate the commands. 313 OnAddEntry();
591 StartSaveTimer();
592 entries_to_write_++;
593 } 314 }
594 315
595 void TabRestoreService::PruneEntries() { 316 void InMemoryTabRestoreService::PruneEntries() {
596 Entries new_entries; 317 Entries new_entries;
597 318
598 for (TabRestoreService::Entries::const_iterator iter = entries_.begin(); 319 for (TabRestoreService::Entries::const_iterator iter = entries_.begin();
599 iter != entries_.end(); ++iter) { 320 iter != entries_.end(); ++iter) {
600 TabRestoreService::Entry* entry = *iter; 321 TabRestoreService::Entry* entry = *iter;
601 322
602 if (FilterEntry(entry) && 323 if (FilterEntry(entry) &&
603 new_entries.size() < kMaxEntries) { 324 new_entries.size() < kMaxEntries) {
604 new_entries.push_back(entry); 325 new_entries.push_back(entry);
605 } else { 326 } else {
606 delete entry; 327 delete entry;
607 } 328 }
608 } 329 }
609 330
610 entries_ = new_entries; 331 entries_ = new_entries;
611 } 332 }
612 333
613 TabRestoreService::Entries::iterator TabRestoreService::GetEntryIteratorById( 334 TabRestoreService::Entries::iterator
614 SessionID::id_type id) { 335 InMemoryTabRestoreService::GetEntryIteratorById(SessionID::id_type id) {
615 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { 336 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) {
616 if ((*i)->id == id) 337 if ((*i)->id == id)
617 return i; 338 return i;
618 339
619 // For Window entries, see if the ID matches a tab. If so, report the window 340 // For Window entries, see if the ID matches a tab. If so, report the window
620 // as the Entry. 341 // as the Entry.
621 if ((*i)->type == WINDOW) { 342 if ((*i)->type == WINDOW) {
622 std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs; 343 std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs;
623 for (std::vector<Tab>::iterator j = tabs.begin(); 344 for (std::vector<Tab>::iterator j = tabs.begin();
624 j != tabs.end(); ++j) { 345 j != tabs.end(); ++j) {
625 if ((*j).id == id) { 346 if ((*j).id == id) {
626 return i; 347 return i;
627 } 348 }
628 } 349 }
629 } 350 }
630 } 351 }
631 return entries_.end(); 352 return entries_.end();
632 } 353 }
633 354
634 void TabRestoreService::ScheduleCommandsForWindow(const Window& window) { 355 // static
635 DCHECK(!window.tabs.empty()); 356 bool InMemoryTabRestoreService::ValidateEntry(Entry* entry) {
636 int selected_tab = window.selected_tab_index; 357 if (entry->type == TAB)
637 int valid_tab_count = 0; 358 return ValidateTab(static_cast<Tab*>(entry));
638 int real_selected_tab = selected_tab; 359
639 for (size_t i = 0; i < window.tabs.size(); ++i) { 360 if (entry->type == WINDOW)
640 if (GetSelectedNavigationIndexToPersist(window.tabs[i]) != -1) { 361 return ValidateWindow(static_cast<Window*>(entry));
641 valid_tab_count++; 362
642 } else if (static_cast<int>(i) < selected_tab) { 363 NOTREACHED();
643 real_selected_tab--; 364 return false;
644 } 365 }
366
367 void InMemoryTabRestoreService::OnClearEntries() {}
368
369 void InMemoryTabRestoreService::OnRestoreEntryById(
370 SessionID::id_type id,
371 Entries::const_iterator entry_iterator) {
372 }
373
374 void InMemoryTabRestoreService::OnAddEntry() {}
375
376 void InMemoryTabRestoreService::PopulateTab(
377 Tab* tab,
378 int index,
379 TabRestoreServiceDelegate* delegate,
380 NavigationController* controller) {
381 const int pending_index = controller->GetPendingEntryIndex();
382 int entry_count = controller->GetEntryCount();
383 if (entry_count == 0 && pending_index == 0)
384 entry_count++;
385 tab->navigations.resize(static_cast<int>(entry_count));
386 for (int i = 0; i < entry_count; ++i) {
387 NavigationEntry* entry = (i == pending_index) ?
388 controller->GetPendingEntry() : controller->GetEntryAtIndex(i);
389 tab->navigations[i] =
390 TabNavigation::FromNavigationEntry(i, *entry);
645 } 391 }
646 if (valid_tab_count == 0) 392 tab->timestamp = TimeNow();
647 return; // No tabs to persist. 393 tab->current_navigation_index = controller->GetCurrentEntryIndex();
394 if (tab->current_navigation_index == -1 && entry_count > 0)
395 tab->current_navigation_index = 0;
396 tab->tabstrip_index = index;
648 397
649 ScheduleCommand( 398 TabContents* tab_contents =
650 CreateWindowCommand(window.id, 399 TabContents::FromWebContents(controller->GetWebContents());
651 std::min(real_selected_tab, valid_tab_count - 1), 400 // tab_contents is NULL in some browser tests.
652 valid_tab_count, 401 if (tab_contents) {
653 window.timestamp)); 402 const extensions::Extension* extension =
654 403 extensions::TabHelper::FromWebContents(controller->GetWebContents())->
655 if (!window.app_name.empty()) { 404 extension_app();
656 ScheduleCommand( 405 if (extension)
657 CreateSetWindowAppNameCommand(kCommandSetWindowAppName, 406 tab->extension_app_id = extension->id();
658 window.id,
659 window.app_name));
660 } 407 }
661 408
662 for (size_t i = 0; i < window.tabs.size(); ++i) { 409 tab->user_agent_override =
663 int selected_index = GetSelectedNavigationIndexToPersist(window.tabs[i]); 410 controller->GetWebContents()->GetUserAgentOverride();
664 if (selected_index != -1) 411
665 ScheduleCommandsForTab(window.tabs[i], selected_index); 412 // TODO(ajwong): This does not correctly handle storage for isolated apps.
413 tab->session_storage_namespace =
414 controller->GetDefaultSessionStorageNamespace();
415
416 // Delegate may be NULL during unit tests.
417 if (delegate) {
418 tab->browser_id = delegate->GetSessionID().id();
419 tab->pinned = delegate->IsTabPinned(tab->tabstrip_index);
666 } 420 }
667 } 421 }
668 422
669 void TabRestoreService::ScheduleCommandsForTab(const Tab& tab, 423 TabRestoreServiceDelegate* InMemoryTabRestoreService::RestoreTab(
670 int selected_index) {
671 const std::vector<TabNavigation>& navigations = tab.navigations;
672 int max_index = static_cast<int>(navigations.size());
673
674 // Determine the first navigation we'll persist.
675 int valid_count_before_selected = 0;
676 int first_index_to_persist = selected_index;
677 for (int i = selected_index - 1; i >= 0 &&
678 valid_count_before_selected < max_persist_navigation_count; --i) {
679 if (ShouldTrackEntry(navigations[i].virtual_url())) {
680 first_index_to_persist = i;
681 valid_count_before_selected++;
682 }
683 }
684
685 // Write the command that identifies the selected tab.
686 ScheduleCommand(
687 CreateSelectedNavigationInTabCommand(tab.id,
688 valid_count_before_selected,
689 tab.timestamp));
690
691 if (tab.pinned) {
692 PinnedStatePayload payload = true;
693 SessionCommand* command =
694 new SessionCommand(kCommandPinnedState, sizeof(payload));
695 memcpy(command->contents(), &payload, sizeof(payload));
696 ScheduleCommand(command);
697 }
698
699 if (!tab.extension_app_id.empty()) {
700 ScheduleCommand(
701 CreateSetTabExtensionAppIDCommand(kCommandSetExtensionAppID, tab.id,
702 tab.extension_app_id));
703 }
704
705 if (!tab.user_agent_override.empty()) {
706 ScheduleCommand(
707 CreateSetTabUserAgentOverrideCommand(kCommandSetTabUserAgentOverride,
708 tab.id, tab.user_agent_override));
709 }
710
711 // Then write the navigations.
712 for (int i = first_index_to_persist, wrote_count = 0;
713 i < max_index && wrote_count < 2 * max_persist_navigation_count; ++i) {
714 if (ShouldTrackEntry(navigations[i].virtual_url())) {
715 ScheduleCommand(
716 CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation, tab.id,
717 navigations[i]));
718 }
719 }
720 }
721
722 SessionCommand* TabRestoreService::CreateWindowCommand(SessionID::id_type id,
723 int selected_tab_index,
724 int num_tabs,
725 Time timestamp) {
726 WindowPayload2 payload;
727 // |timestamp| is aligned on a 16 byte boundary, leaving 4 bytes of
728 // uninitialized memory in the struct.
729 memset(&payload, 0, sizeof(payload));
730 payload.window_id = id;
731 payload.selected_tab_index = selected_tab_index;
732 payload.num_tabs = num_tabs;
733 payload.timestamp = timestamp.ToInternalValue();
734
735 SessionCommand* command =
736 new SessionCommand(kCommandWindow, sizeof(payload));
737 memcpy(command->contents(), &payload, sizeof(payload));
738 return command;
739 }
740
741 SessionCommand* TabRestoreService::CreateSelectedNavigationInTabCommand(
742 SessionID::id_type tab_id,
743 int32 index,
744 Time timestamp) {
745 SelectedNavigationInTabPayload2 payload;
746 payload.id = tab_id;
747 payload.index = index;
748 payload.timestamp = timestamp.ToInternalValue();
749 SessionCommand* command =
750 new SessionCommand(kCommandSelectedNavigationInTab, sizeof(payload));
751 memcpy(command->contents(), &payload, sizeof(payload));
752 return command;
753 }
754
755 SessionCommand* TabRestoreService::CreateRestoredEntryCommand(
756 SessionID::id_type entry_id) {
757 RestoredEntryPayload payload = entry_id;
758 SessionCommand* command =
759 new SessionCommand(kCommandRestoredEntry, sizeof(payload));
760 memcpy(command->contents(), &payload, sizeof(payload));
761 return command;
762 }
763
764 int TabRestoreService::GetSelectedNavigationIndexToPersist(const Tab& tab) {
765 const std::vector<TabNavigation>& navigations = tab.navigations;
766 int selected_index = tab.current_navigation_index;
767 int max_index = static_cast<int>(navigations.size());
768
769 // Find the first navigation to persist. We won't persist the selected
770 // navigation if ShouldTrackEntry returns false.
771 while (selected_index >= 0 &&
772 !ShouldTrackEntry(navigations[selected_index].virtual_url())) {
773 selected_index--;
774 }
775
776 if (selected_index != -1)
777 return selected_index;
778
779 // Couldn't find a navigation to persist going back, go forward.
780 selected_index = tab.current_navigation_index + 1;
781 while (selected_index < max_index &&
782 !ShouldTrackEntry(navigations[selected_index].virtual_url())) {
783 selected_index++;
784 }
785
786 return (selected_index == max_index) ? -1 : selected_index;
787 }
788
789 void TabRestoreService::OnGotLastSessionCommands(
790 Handle handle,
791 scoped_refptr<InternalGetCommandsRequest> request) {
792 std::vector<Entry*> entries;
793 CreateEntriesFromCommands(request, &entries);
794 // Closed tabs always go to the end.
795 staging_entries_.insert(staging_entries_.end(), entries.begin(),
796 entries.end());
797 load_state_ |= LOADED_LAST_TABS;
798 LoadStateChanged();
799 }
800
801 void TabRestoreService::CreateEntriesFromCommands(
802 scoped_refptr<InternalGetCommandsRequest> request,
803 std::vector<Entry*>* loaded_entries) {
804 if (request->canceled() || entries_.size() == kMaxEntries)
805 return;
806
807 std::vector<SessionCommand*>& commands = request->commands;
808 // Iterate through the commands populating entries and id_to_entry.
809 ScopedVector<Entry> entries;
810 IDToEntry id_to_entry;
811 // If non-null we're processing the navigations of this tab.
812 Tab* current_tab = NULL;
813 // If non-null we're processing the tabs of this window.
814 Window* current_window = NULL;
815 // If > 0, we've gotten a window command but not all the tabs yet.
816 int pending_window_tabs = 0;
817 for (std::vector<SessionCommand*>::const_iterator i = commands.begin();
818 i != commands.end(); ++i) {
819 const SessionCommand& command = *(*i);
820 switch (command.id()) {
821 case kCommandRestoredEntry: {
822 if (pending_window_tabs > 0) {
823 // Should never receive a restored command while waiting for all the
824 // tabs in a window.
825 return;
826 }
827
828 current_tab = NULL;
829 current_window = NULL;
830
831 RestoredEntryPayload payload;
832 if (!command.GetPayload(&payload, sizeof(payload)))
833 return;
834 RemoveEntryByID(payload, &id_to_entry, &(entries.get()));
835 break;
836 }
837
838 case kCommandWindow: {
839 WindowPayload2 payload;
840 if (pending_window_tabs > 0) {
841 // Should never receive a window command while waiting for all the
842 // tabs in a window.
843 return;
844 }
845
846 // Try the new payload first
847 if (!command.GetPayload(&payload, sizeof(payload))) {
848 // then the old payload
849 WindowPayload old_payload;
850 if (!command.GetPayload(&old_payload, sizeof(old_payload)))
851 return;
852
853 // Copy the old payload data to the new payload.
854 payload.window_id = old_payload.window_id;
855 payload.selected_tab_index = old_payload.selected_tab_index;
856 payload.num_tabs = old_payload.num_tabs;
857 // Since we don't have a time use time 0 which is used to mark as an
858 // unknown timestamp.
859 payload.timestamp = 0;
860 }
861
862 pending_window_tabs = payload.num_tabs;
863 if (pending_window_tabs <= 0) {
864 // Should always have at least 1 tab. Likely indicates corruption.
865 return;
866 }
867
868 RemoveEntryByID(payload.window_id, &id_to_entry, &(entries.get()));
869
870 current_window = new Window();
871 current_window->selected_tab_index = payload.selected_tab_index;
872 current_window->timestamp = Time::FromInternalValue(payload.timestamp);
873 entries.push_back(current_window);
874 id_to_entry[payload.window_id] = current_window;
875 break;
876 }
877
878 case kCommandSelectedNavigationInTab: {
879 SelectedNavigationInTabPayload2 payload;
880 if (!command.GetPayload(&payload, sizeof(payload))) {
881 SelectedNavigationInTabPayload old_payload;
882 if (!command.GetPayload(&old_payload, sizeof(old_payload)))
883 return;
884 payload.id = old_payload.id;
885 payload.index = old_payload.index;
886 // Since we don't have a time use time 0 which is used to mark as an
887 // unknown timestamp.
888 payload.timestamp = 0;
889 }
890
891 if (pending_window_tabs > 0) {
892 if (!current_window) {
893 // We should have created a window already.
894 NOTREACHED();
895 return;
896 }
897 current_window->tabs.resize(current_window->tabs.size() + 1);
898 current_tab = &(current_window->tabs.back());
899 if (--pending_window_tabs == 0)
900 current_window = NULL;
901 } else {
902 RemoveEntryByID(payload.id, &id_to_entry, &(entries.get()));
903 current_tab = new Tab();
904 id_to_entry[payload.id] = current_tab;
905 current_tab->timestamp = Time::FromInternalValue(payload.timestamp);
906 entries.push_back(current_tab);
907 }
908 current_tab->current_navigation_index = payload.index;
909 break;
910 }
911
912 case kCommandUpdateTabNavigation: {
913 if (!current_tab) {
914 // Should be in a tab when we get this.
915 return;
916 }
917 current_tab->navigations.resize(current_tab->navigations.size() + 1);
918 SessionID::id_type tab_id;
919 if (!RestoreUpdateTabNavigationCommand(
920 command, &current_tab->navigations.back(), &tab_id)) {
921 return;
922 }
923 break;
924 }
925
926 case kCommandPinnedState: {
927 if (!current_tab) {
928 // Should be in a tab when we get this.
929 return;
930 }
931 // NOTE: payload doesn't matter. kCommandPinnedState is only written if
932 // tab is pinned.
933 current_tab->pinned = true;
934 break;
935 }
936
937 case kCommandSetWindowAppName: {
938 if (!current_window) {
939 // We should have created a window already.
940 NOTREACHED();
941 return;
942 }
943
944 SessionID::id_type window_id;
945 std::string app_name;
946 if (!RestoreSetWindowAppNameCommand(command, &window_id, &app_name))
947 return;
948
949 current_window->app_name.swap(app_name);
950 break;
951 }
952
953 case kCommandSetExtensionAppID: {
954 if (!current_tab) {
955 // Should be in a tab when we get this.
956 return;
957 }
958 SessionID::id_type tab_id;
959 std::string extension_app_id;
960 if (!RestoreSetTabExtensionAppIDCommand(command, &tab_id,
961 &extension_app_id)) {
962 return;
963 }
964 current_tab->extension_app_id.swap(extension_app_id);
965 break;
966 }
967
968 case kCommandSetTabUserAgentOverride: {
969 if (!current_tab) {
970 // Should be in a tab when we get this.
971 return;
972 }
973 SessionID::id_type tab_id;
974 std::string user_agent_override;
975 if (!RestoreSetTabUserAgentOverrideCommand(command, &tab_id,
976 &user_agent_override)) {
977 return;
978 }
979 current_tab->user_agent_override.swap(user_agent_override);
980 break;
981 }
982
983 default:
984 // Unknown type, usually indicates corruption of file. Ignore it.
985 return;
986 }
987 }
988
989 // If there was corruption some of the entries won't be valid.
990 ValidateAndDeleteEmptyEntries(&(entries.get()));
991
992 loaded_entries->swap(entries.get());
993 }
994
995 TabRestoreServiceDelegate* TabRestoreService::RestoreTab(
996 const Tab& tab, 424 const Tab& tab,
997 TabRestoreServiceDelegate* delegate, 425 TabRestoreServiceDelegate* delegate,
998 WindowOpenDisposition disposition) { 426 WindowOpenDisposition disposition) {
999 if (disposition == CURRENT_TAB && delegate) { 427 if (disposition == CURRENT_TAB && delegate) {
1000 delegate->ReplaceRestoredTab(tab.navigations, 428 delegate->ReplaceRestoredTab(tab.navigations,
1001 tab.current_navigation_index, 429 tab.current_navigation_index,
1002 tab.from_last_session, 430 tab.from_last_session,
1003 tab.extension_app_id, 431 tab.extension_app_id,
1004 tab.session_storage_namespace, 432 tab.session_storage_namespace,
1005 tab.user_agent_override); 433 tab.user_agent_override);
1006 } else { 434 } else {
1007 // We only respsect the tab's original browser if there's no disposition. 435 // We only respsect the tab's original browser if there's no disposition.
1008 if (disposition == UNKNOWN && tab.has_browser()) 436 if (disposition == UNKNOWN && tab.has_browser())
1009 delegate = TabRestoreServiceDelegate::FindDelegateWithID(tab.browser_id); 437 delegate = TabRestoreServiceDelegate::FindDelegateWithID(tab.browser_id);
1010 438
1011 int tab_index = -1; 439 int tab_index = -1;
1012 440
1013 // |delegate| will be NULL in cases where one isn't already available (eg, 441 // |delegate| will be NULL in cases where one isn't already available (eg,
1014 // when invoked on Mac OS X with no windows open). In this case, create a 442 // when invoked on Mac OS X with no windows open). In this case, create a
1015 // new browser into which we restore the tabs. 443 // new browser into which we restore the tabs.
1016 if (delegate && disposition != NEW_WINDOW) { 444 if (delegate && disposition != NEW_WINDOW) {
1017 tab_index = tab.tabstrip_index; 445 tab_index = tab.tabstrip_index;
1018 } else { 446 } else {
1019 delegate = TabRestoreServiceDelegate::Create(profile(), std::string()); 447 delegate = TabRestoreServiceDelegate::Create(profile_, std::string());
1020 if (tab.has_browser()) 448 if (tab.has_browser())
1021 UpdateTabBrowserIDs(tab.browser_id, delegate->GetSessionID().id()); 449 UpdateTabBrowserIDs(tab.browser_id, delegate->GetSessionID().id());
1022 } 450 }
1023 451
1024 // Place the tab at the end if the tab index is no longer valid or 452 // Place the tab at the end if the tab index is no longer valid or
1025 // we were passed a specific disposition. 453 // we were passed a specific disposition.
1026 if (tab_index < 0 || tab_index > delegate->GetTabCount() || 454 if (tab_index < 0 || tab_index > delegate->GetTabCount() ||
1027 disposition != UNKNOWN) { 455 disposition != UNKNOWN) {
1028 tab_index = delegate->GetTabCount(); 456 tab_index = delegate->GetTabCount();
1029 } 457 }
1030 458
1031 WebContents* web_contents = delegate->AddRestoredTab( 459 WebContents* web_contents = delegate->AddRestoredTab(
1032 tab.navigations, 460 tab.navigations,
1033 tab_index, 461 tab_index,
1034 tab.current_navigation_index, 462 tab.current_navigation_index,
1035 tab.extension_app_id, 463 tab.extension_app_id,
1036 disposition != NEW_BACKGROUND_TAB, 464 disposition != NEW_BACKGROUND_TAB,
1037 tab.pinned, 465 tab.pinned,
1038 tab.from_last_session, 466 tab.from_last_session,
1039 tab.session_storage_namespace, 467 tab.session_storage_namespace,
1040 tab.user_agent_override); 468 tab.user_agent_override);
1041 web_contents->GetController().LoadIfNecessary(); 469 web_contents->GetController().LoadIfNecessary();
1042 } 470 }
1043 RecordAppLaunch(profile(), tab); 471 RecordAppLaunch(profile_, tab);
1044 return delegate; 472 return delegate;
1045 } 473 }
1046 474
1047 475
1048 bool TabRestoreService::ValidateTab(Tab* tab) { 476 bool InMemoryTabRestoreService::ValidateTab(Tab* tab) {
1049 if (tab->navigations.empty()) 477 if (tab->navigations.empty())
1050 return false; 478 return false;
1051 479
1052 tab->current_navigation_index = 480 tab->current_navigation_index =
1053 std::max(0, std::min(tab->current_navigation_index, 481 std::max(0, std::min(tab->current_navigation_index,
1054 static_cast<int>(tab->navigations.size()) - 1)); 482 static_cast<int>(tab->navigations.size()) - 1));
1055 483
1056 return true; 484 return true;
1057 } 485 }
1058 486
1059 bool TabRestoreService::ValidateWindow(Window* window) { 487 bool InMemoryTabRestoreService::ValidateWindow(Window* window) {
1060 window->selected_tab_index = 488 window->selected_tab_index =
1061 std::max(0, std::min(window->selected_tab_index, 489 std::max(0, std::min(window->selected_tab_index,
1062 static_cast<int>(window->tabs.size() - 1))); 490 static_cast<int>(window->tabs.size() - 1)));
1063 491
1064 int i = 0; 492 int i = 0;
1065 for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); 493 for (std::vector<Tab>::iterator tab_i = window->tabs.begin();
1066 tab_i != window->tabs.end();) { 494 tab_i != window->tabs.end();) {
1067 if (!ValidateTab(&(*tab_i))) { 495 if (!ValidateTab(&(*tab_i))) {
1068 tab_i = window->tabs.erase(tab_i); 496 tab_i = window->tabs.erase(tab_i);
1069 if (i < window->selected_tab_index) 497 if (i < window->selected_tab_index)
1070 window->selected_tab_index--; 498 window->selected_tab_index--;
1071 else if (i == window->selected_tab_index) 499 else if (i == window->selected_tab_index)
1072 window->selected_tab_index = 0; 500 window->selected_tab_index = 0;
1073 } else { 501 } else {
1074 ++tab_i; 502 ++tab_i;
1075 ++i; 503 ++i;
1076 } 504 }
1077 } 505 }
1078 506
1079 if (window->tabs.empty()) 507 if (window->tabs.empty())
1080 return false; 508 return false;
1081 509
1082 return true; 510 return true;
1083 } 511 }
1084 512
1085 bool TabRestoreService::ValidateEntry(Entry* entry) { 513 bool InMemoryTabRestoreService::IsTabInteresting(const Tab* tab) {
1086 if (entry->type == TAB)
1087 return ValidateTab(static_cast<Tab*>(entry));
1088
1089 if (entry->type == WINDOW)
1090 return ValidateWindow(static_cast<Window*>(entry));
1091
1092 NOTREACHED();
1093 return false;
1094 }
1095
1096 bool TabRestoreService::IsTabInteresting(const Tab* tab) {
1097 if (tab->navigations.empty()) 514 if (tab->navigations.empty())
1098 return false; 515 return false;
1099 516
1100 if (tab->navigations.size() > 1) 517 if (tab->navigations.size() > 1)
1101 return true; 518 return true;
1102 519
1103 return tab->pinned || 520 return tab->pinned ||
1104 tab->navigations.at(0).virtual_url() != 521 tab->navigations.at(0).virtual_url() !=
1105 GURL(chrome::kChromeUINewTabURL); 522 GURL(chrome::kChromeUINewTabURL);
1106 } 523 }
1107 524
1108 bool TabRestoreService::IsWindowInteresting(const Window* window) { 525 bool InMemoryTabRestoreService::IsWindowInteresting(const Window* window) {
1109 if (window->tabs.empty()) 526 if (window->tabs.empty())
1110 return false; 527 return false;
1111 528
1112 if (window->tabs.size() > 1) 529 if (window->tabs.size() > 1)
1113 return true; 530 return true;
1114 531
1115 return IsTabInteresting(&window->tabs[0]); 532 return IsTabInteresting(&window->tabs[0]);
1116 } 533 }
1117 534
1118 bool TabRestoreService::FilterEntry(Entry* entry) { 535 bool InMemoryTabRestoreService::FilterEntry(Entry* entry) {
1119 if (!ValidateEntry(entry)) 536 if (!ValidateEntry(entry))
1120 return false; 537 return false;
1121 538
1122 if (entry->type == TAB) 539 if (entry->type == TAB)
1123 return IsTabInteresting(static_cast<Tab*>(entry)); 540 return IsTabInteresting(static_cast<Tab*>(entry));
1124 else if (entry->type == WINDOW) 541 else if (entry->type == WINDOW)
1125 return IsWindowInteresting(static_cast<Window*>(entry)); 542 return IsWindowInteresting(static_cast<Window*>(entry));
1126 543
1127 NOTREACHED(); 544 NOTREACHED();
1128 return false; 545 return false;
1129 } 546 }
1130 547
1131 void TabRestoreService::ValidateAndDeleteEmptyEntries( 548 void InMemoryTabRestoreService::UpdateTabBrowserIDs(SessionID::id_type old_id,
1132 std::vector<Entry*>* entries) { 549 SessionID::id_type new_id) {
1133 std::vector<Entry*> valid_entries;
1134 std::vector<Entry*> invalid_entries;
1135
1136 // Iterate from the back so that we keep the most recently closed entries.
1137 for (std::vector<Entry*>::reverse_iterator i = entries->rbegin();
1138 i != entries->rend(); ++i) {
1139 if (ValidateEntry(*i))
1140 valid_entries.push_back(*i);
1141 else
1142 invalid_entries.push_back(*i);
1143 }
1144 // NOTE: at this point the entries are ordered with newest at the front.
1145 entries->swap(valid_entries);
1146
1147 // Delete the remaining entries.
1148 STLDeleteElements(&invalid_entries);
1149 }
1150
1151 void TabRestoreService::UpdateTabBrowserIDs(SessionID::id_type old_id,
1152 SessionID::id_type new_id) {
1153 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { 550 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) {
1154 Entry* entry = *i; 551 Entry* entry = *i;
1155 if (entry->type == TAB) { 552 if (entry->type == TAB) {
1156 Tab* tab = static_cast<Tab*>(entry); 553 Tab* tab = static_cast<Tab*>(entry);
1157 if (tab->browser_id == old_id) 554 if (tab->browser_id == old_id)
1158 tab->browser_id = new_id; 555 tab->browser_id = new_id;
1159 } 556 }
1160 } 557 }
1161 } 558 }
1162 559
1163 void TabRestoreService::OnGotPreviousSession( 560 base::Time InMemoryTabRestoreService::TimeNow() const {
1164 Handle handle, 561 return time_factory_ ? time_factory_->TimeNow() : base::Time::Now();
1165 std::vector<SessionWindow*>* windows,
1166 SessionID::id_type ignored_active_window) {
1167 std::vector<Entry*> entries;
1168 CreateEntriesFromWindows(windows, &entries);
1169 // Previous session tabs go first.
1170 staging_entries_.insert(staging_entries_.begin(), entries.begin(),
1171 entries.end());
1172 load_state_ |= LOADED_LAST_SESSION;
1173 LoadStateChanged();
1174 } 562 }
1175
1176 void TabRestoreService::CreateEntriesFromWindows(
1177 std::vector<SessionWindow*>* windows,
1178 std::vector<Entry*>* entries) {
1179 for (size_t i = 0; i < windows->size(); ++i) {
1180 scoped_ptr<Window> window(new Window());
1181 if (ConvertSessionWindowToWindow((*windows)[i], window.get()))
1182 entries->push_back(window.release());
1183 }
1184 }
1185
1186 bool TabRestoreService::ConvertSessionWindowToWindow(
1187 SessionWindow* session_window,
1188 Window* window) {
1189 for (size_t i = 0; i < session_window->tabs.size(); ++i) {
1190 if (!session_window->tabs[i]->navigations.empty()) {
1191 window->tabs.resize(window->tabs.size() + 1);
1192 Tab& tab = window->tabs.back();
1193 tab.pinned = session_window->tabs[i]->pinned;
1194 tab.navigations.swap(session_window->tabs[i]->navigations);
1195 tab.current_navigation_index =
1196 session_window->tabs[i]->current_navigation_index;
1197 tab.extension_app_id = session_window->tabs[i]->extension_app_id;
1198 tab.timestamp = Time();
1199 }
1200 }
1201 if (window->tabs.empty())
1202 return false;
1203
1204 window->selected_tab_index =
1205 std::min(session_window->selected_tab_index,
1206 static_cast<int>(window->tabs.size() - 1));
1207 window->timestamp = Time();
1208 return true;
1209 }
1210
1211 void TabRestoreService::LoadStateChanged() {
1212 if ((load_state_ & (LOADED_LAST_TABS | LOADED_LAST_SESSION)) !=
1213 (LOADED_LAST_TABS | LOADED_LAST_SESSION)) {
1214 // Still waiting on previous session or previous tabs.
1215 return;
1216 }
1217
1218 // We're done loading.
1219 load_state_ ^= LOADING;
1220
1221 if (staging_entries_.empty() || entries_.size() >= kMaxEntries) {
1222 STLDeleteElements(&staging_entries_);
1223 return;
1224 }
1225
1226 if (staging_entries_.size() + entries_.size() > kMaxEntries) {
1227 // If we add all the staged entries we'll end up with more than
1228 // kMaxEntries. Delete entries such that we only end up with
1229 // at most kMaxEntries.
1230 int surplus = kMaxEntries - entries_.size();
1231 CHECK_LE(0, surplus);
1232 CHECK_GE(static_cast<int>(staging_entries_.size()), surplus);
1233 STLDeleteContainerPointers(
1234 staging_entries_.begin() + (kMaxEntries - entries_.size()),
1235 staging_entries_.end());
1236 staging_entries_.erase(
1237 staging_entries_.begin() + (kMaxEntries - entries_.size()),
1238 staging_entries_.end());
1239 }
1240
1241 // And add them.
1242 for (size_t i = 0; i < staging_entries_.size(); ++i) {
1243 staging_entries_[i]->from_last_session = true;
1244 AddEntry(staging_entries_[i], false, false);
1245 }
1246
1247 // AddEntry takes ownership of the entry, need to clear out entries so that
1248 // it doesn't delete them.
1249 staging_entries_.clear();
1250
1251 // Make it so we rewrite all the tabs. We need to do this otherwise we won't
1252 // correctly write out the entries when Save is invoked (Save starts from
1253 // the front, not the end and we just added the entries to the end).
1254 entries_to_write_ = staging_entries_.size();
1255
1256 PruneEntries();
1257 NotifyTabsChanged();
1258 }
1259
1260 Time TabRestoreService::TimeNow() const {
1261 return time_factory_ ? time_factory_->TimeNow() : Time::Now();
1262 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698