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

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

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

Powered by Google App Engine
This is Rietveld 408576698