blob: 71dd17732ba1fdee16cb3626ed36145180d06c58 [file] [log] [blame]
[email protected]ebbbb9f2011-03-09 13:16:141// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]169627b2008-12-06 19:30:195#ifndef CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_
6#define CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_
[email protected]32b76ef2010-07-26 23:08:247#pragma once
initial.commit09911bf2008-07-26 23:55:298
9#include <map>
[email protected]23da84e152010-07-14 01:29:0510#include <string>
initial.commit09911bf2008-07-26 23:55:2911
12#include "base/basictypes.h"
[email protected]2041cf342010-02-19 03:15:5913#include "base/callback.h"
[email protected]70eb8ed92010-06-10 18:13:1214#include "base/time.h"
[email protected]982921f12009-10-27 21:43:5315#include "chrome/browser/defaults.h"
[email protected]926bfeb2009-02-14 23:19:4716#include "chrome/browser/sessions/base_session_service.h"
[email protected]169627b2008-12-06 19:30:1917#include "chrome/browser/sessions/session_id.h"
[email protected]2ad4a902010-11-17 06:05:1318#include "chrome/browser/ui/browser.h"
19#include "chrome/browser/ui/browser_list.h"
[email protected]ebbbb9f2011-03-09 13:16:1420#include "content/common/notification_observer.h"
21#include "content/common/notification_registrar.h"
initial.commit09911bf2008-07-26 23:55:2922
initial.commit09911bf2008-07-26 23:55:2923class NavigationEntry;
24class Profile;
initial.commit09911bf2008-07-26 23:55:2925class SessionCommand;
[email protected]169627b2008-12-06 19:30:1926struct SessionTab;
27struct SessionWindow;
[email protected]81898992011-06-14 22:15:0028class TabContentsWrapper;
initial.commit09911bf2008-07-26 23:55:2929
30// SessionService ------------------------------------------------------------
31
32// SessionService is responsible for maintaining the state of open windows
[email protected]6ea265a2008-10-30 02:58:3633// and tabs so that they can be restored at a later date. The state of the
34// currently open browsers is referred to as the current session.
initial.commit09911bf2008-07-26 23:55:2935//
[email protected]668cd422011-04-06 21:00:0136// SessionService supports restoring from the last session. The last session
37// typically corresponds to the last run of the browser, but not always. For
38// example, if the user has a tabbed browser and app window running, closes the
39// tabbed browser, then creates a new tabbed browser the current session is made
40// the last session and the current session reset. This is done to provide the
41// illusion that app windows run in separate processes. Similar behavior occurs
42// with incognito windows.
initial.commit09911bf2008-07-26 23:55:2943//
44// SessionService itself maintains a set of SessionCommands that allow
45// SessionService to rebuild the open state of the browser (as
46// SessionWindow, SessionTab and TabNavigation). The commands are periodically
47// flushed to SessionBackend and written to a file. Every so often
48// SessionService rebuilds the contents of the file from the open state
49// of the browser.
[email protected]169627b2008-12-06 19:30:1950class SessionService : public BaseSessionService,
51 public NotificationObserver {
initial.commit09911bf2008-07-26 23:55:2952 friend class SessionServiceTestHelper;
53 public:
54 // Creates a SessionService for the specified profile.
55 explicit SessionService(Profile* profile);
56 // For testing.
[email protected]5a82010a2009-02-14 01:33:0257 explicit SessionService(const FilePath& save_path);
initial.commit09911bf2008-07-26 23:55:2958
[email protected]f0a58a382011-04-26 16:09:2959 virtual ~SessionService();
60
[email protected]c9b19942010-03-26 15:58:0861 // Invoke at a point when you think session restore might occur. For example,
62 // during startup and window creation this is invoked to see if a session
63 // needs to be restored. If a session needs to be restored it is done so
64 // asynchronously and true is returned. If false is returned the session was
65 // not restored and the caller needs to create a new window.
66 bool RestoreIfNecessary(const std::vector<GURL>& urls_to_open);
67
initial.commit09911bf2008-07-26 23:55:2968 // Resets the contents of the file from the current state of all open
69 // browsers whose profile matches our profile.
70 void ResetFromCurrentBrowsers();
71
72 // Moves the current session to the last session. This is useful when a
73 // checkpoint occurs, such as when the user launches the app and no tabbed
74 // browsers are running.
75 void MoveCurrentSessionToLastSession();
76
77 // Associates a tab with a window.
78 void SetTabWindow(const SessionID& window_id,
79 const SessionID& tab_id);
80
81 // Sets the bounds of a window.
82 void SetWindowBounds(const SessionID& window_id,
83 const gfx::Rect& bounds,
84 bool is_maximized);
85
86 // Sets the visual index of the tab in its parent window.
87 void SetTabIndexInWindow(const SessionID& window_id,
88 const SessionID& tab_id,
89 int new_index);
90
[email protected]5c0e6482009-07-14 20:20:0991 // Sets the pinned state of the tab.
92 void SetPinnedState(const SessionID& window_id,
93 const SessionID& tab_id,
94 bool is_pinned);
95
[email protected]c0e3ee42010-05-26 22:11:0796 // Notification that a tab has been closed. |closed_by_user_gesture| comes
97 // from |TabContents::closed_by_user_gesture|; see it for details.
initial.commit09911bf2008-07-26 23:55:2998 //
99 // Note: this is invoked from the NavigationController's destructor, which is
100 // after the actual tab has been removed.
[email protected]c0e3ee42010-05-26 22:11:07101 void TabClosed(const SessionID& window_id,
102 const SessionID& tab_id,
103 bool closed_by_user_gesture);
initial.commit09911bf2008-07-26 23:55:29104
105 // Notification the window is about to close.
106 void WindowClosing(const SessionID& window_id);
107
108 // Notification a window has finished closing.
109 void WindowClosed(const SessionID& window_id);
110
111 // Sets the type of window. In order for the contents of a window to be
112 // tracked SetWindowType must be invoked with a type we track
113 // (should_track_changes_for_browser_type returns true).
[email protected]299dabd2008-11-19 02:27:16114 void SetWindowType(const SessionID& window_id, Browser::Type type);
initial.commit09911bf2008-07-26 23:55:29115
[email protected]c12bf1a12008-09-17 16:28:49116 // Invoked when the NavigationController has removed entries from the back of
117 // the list. |count| gives the number of entries in the navigation controller.
118 void TabNavigationPathPrunedFromBack(const SessionID& window_id,
119 const SessionID& tab_id,
120 int count);
121
122 // Invoked when the NavigationController has removed entries from the front of
123 // the list. |count| gives the number of entries that were removed.
124 void TabNavigationPathPrunedFromFront(const SessionID& window_id,
125 const SessionID& tab_id,
126 int count);
initial.commit09911bf2008-07-26 23:55:29127
128 // Updates the navigation entry for the specified tab.
129 void UpdateTabNavigation(const SessionID& window_id,
130 const SessionID& tab_id,
131 int index,
132 const NavigationEntry& entry);
133
134 // Notification that a tab has restored its entries or a closed tab is being
135 // reused.
[email protected]81898992011-06-14 22:15:00136 void TabRestored(TabContentsWrapper* tab, bool pinned);
initial.commit09911bf2008-07-26 23:55:29137
138 // Sets the index of the selected entry in the navigation controller for the
139 // specified tab.
140 void SetSelectedNavigationIndex(const SessionID& window_id,
141 const SessionID& tab_id,
142 int index);
143
144 // Sets the index of the selected tab in the specified window.
145 void SetSelectedTabInWindow(const SessionID& window_id, int index);
146
147 // Callback from GetSavedSession of GetLastSession.
148 //
149 // The contents of the supplied vector are deleted after the callback is
150 // notified. To take ownership of the vector clear it before returning.
151 //
152 // The time gives the time the session was closed.
153 typedef Callback2<Handle, std::vector<SessionWindow*>*>::Type
[email protected]3acb70ef2010-03-01 18:44:38154 SessionCallback;
initial.commit09911bf2008-07-26 23:55:29155
156 // Fetches the contents of the last session, notifying the callback when
157 // done. If the callback is supplied an empty vector of SessionWindows
158 // it means the session could not be restored.
[email protected]169627b2008-12-06 19:30:19159 //
160 // The created request does NOT directly invoke the callback, rather the
161 // callback invokes OnGotSessionCommands from which we map the
162 // SessionCommands to browser state, then notify the callback.
initial.commit09911bf2008-07-26 23:55:29163 Handle GetLastSession(CancelableRequestConsumerBase* consumer,
[email protected]3acb70ef2010-03-01 18:44:38164 SessionCallback* callback);
165
166 // Fetches the contents of the current session, notifying the callback when
167 // done. If the callback is supplied an empty vector of SessionWindows
168 // it means the session could not be restored.
169 //
170 // The created request does NOT directly invoke the callback, rather the
171 // callback invokes OnGotSessionCommands from which we map the
172 // SessionCommands to browser state, then notify the callback.
173 Handle GetCurrentSession(CancelableRequestConsumerBase* consumer,
174 SessionCallback* callback);
initial.commit09911bf2008-07-26 23:55:29175
[email protected]70eb8ed92010-06-10 18:13:12176 // Overridden from BaseSessionService because we want some UMA reporting on
177 // session update activities.
178 virtual void Save();
179
initial.commit09911bf2008-07-26 23:55:29180 private:
[email protected]23da84e152010-07-14 01:29:05181 typedef std::map<SessionID::id_type, std::pair<int, int> > IdToRange;
182 typedef std::map<SessionID::id_type, SessionTab*> IdToSessionTab;
183 typedef std::map<SessionID::id_type, SessionWindow*> IdToSessionWindow;
184
initial.commit09911bf2008-07-26 23:55:29185
[email protected]97d2c1e2009-11-05 03:55:05186 // These types mirror Browser::Type, but are re-defined here because these
187 // specific enumeration _values_ are written into the session database and
188 // are needed to maintain forward compatibility.
[email protected]b35b26b32011-05-05 20:35:14189 // Note that we only store browsers of type TYPE_TABBED and TYPE_POPUP.
[email protected]97d2c1e2009-11-05 03:55:05190 enum WindowType {
[email protected]b35b26b32011-05-05 20:35:14191 TYPE_TABBED = 0,
192 TYPE_POPUP = 1
[email protected]97d2c1e2009-11-05 03:55:05193 };
194
[email protected]169627b2008-12-06 19:30:19195 void Init();
initial.commit09911bf2008-07-26 23:55:29196
[email protected]c9b19942010-03-26 15:58:08197 // Implementation of RestoreIfNecessary. If |browser| is non-null and we need
198 // to restore, the tabs are added to it, otherwise a new browser is created.
199 bool RestoreIfNecessary(const std::vector<GURL>& urls_to_open,
200 Browser* browser);
201
[email protected]432115822011-07-10 15:52:27202 virtual void Observe(int type,
[email protected]534e54b2008-08-13 15:40:09203 const NotificationSource& source,
204 const NotificationDetails& details);
205
[email protected]fca656c2010-02-10 20:30:10206 // Sets the application extension id of the specified tab.
[email protected]98aa0b52010-05-06 17:03:08207 void SetTabExtensionAppID(const SessionID& window_id,
[email protected]fca656c2010-02-10 20:30:10208 const SessionID& tab_id,
[email protected]98aa0b52010-05-06 17:03:08209 const std::string& extension_app_id);
[email protected]fca656c2010-02-10 20:30:10210
initial.commit09911bf2008-07-26 23:55:29211 // Methods to create the various commands. It is up to the caller to delete
212 // the returned the SessionCommand* object.
213 SessionCommand* CreateSetSelectedTabInWindow(const SessionID& window_id,
214 int index);
215
216 SessionCommand* CreateSetTabWindowCommand(const SessionID& window_id,
217 const SessionID& tab_id);
218
219 SessionCommand* CreateSetWindowBoundsCommand(const SessionID& window_id,
220 const gfx::Rect& bounds,
221 bool is_maximized);
222
223 SessionCommand* CreateSetTabIndexInWindowCommand(const SessionID& tab_id,
224 int new_index);
225
226 SessionCommand* CreateTabClosedCommand(SessionID::id_type tab_id);
227
228 SessionCommand* CreateWindowClosedCommand(SessionID::id_type tab_id);
229
initial.commit09911bf2008-07-26 23:55:29230 SessionCommand* CreateSetSelectedNavigationIndexCommand(
231 const SessionID& tab_id,
232 int index);
233
234 SessionCommand* CreateSetWindowTypeCommand(const SessionID& window_id,
[email protected]97d2c1e2009-11-05 03:55:05235 WindowType type);
initial.commit09911bf2008-07-26 23:55:29236
[email protected]5c0e6482009-07-14 20:20:09237 SessionCommand* CreatePinnedStateCommand(const SessionID& tab_id,
238 bool is_pinned);
239
[email protected]668cd422011-04-06 21:00:01240 // Callback from the backend for getting the commands from the save file.
241 // Converts the commands in SessionWindows and notifies the real callback.
[email protected]3acb70ef2010-03-01 18:44:38242 void OnGotSessionCommands(
initial.commit09911bf2008-07-26 23:55:29243 Handle handle,
[email protected]169627b2008-12-06 19:30:19244 scoped_refptr<InternalGetCommandsRequest> request);
initial.commit09911bf2008-07-26 23:55:29245
246 // Converts the commands into SessionWindows. On return any valid
247 // windows are added to valid_windows. It is up to the caller to delete
248 // the windows added to valid_windows.
249 //
250 // If ignore_recent_closes is true, any window/tab closes within in a certain
251 // time frame are ignored.
252 void RestoreSessionFromCommands(const std::vector<SessionCommand*>& commands,
253 std::vector<SessionWindow*>* valid_windows);
254
255 // Iterates through the vector updating the selected_tab_index of each
256 // SessionWindow based on the actual tabs that were restored.
257 void UpdateSelectedTabIndex(std::vector<SessionWindow*>* windows);
258
259 // Returns the window in windows with the specified id. If a window does
260 // not exist, one is created.
261 SessionWindow* GetWindow(SessionID::id_type window_id,
262 IdToSessionWindow* windows);
263
264 // Returns the tab with the specified id in tabs. If a tab does not exist,
265 // it is created.
266 SessionTab* GetTab(SessionID::id_type tab_id,
267 IdToSessionTab* tabs);
268
269 // Returns an iterator into navigations pointing to the navigation whose
270 // index matches |index|. If no navigation index matches |index|, the first
271 // navigation with an index > |index| is returned.
272 //
273 // This assumes the navigations are ordered by index in ascending order.
274 std::vector<TabNavigation>::iterator FindClosestNavigationWithIndex(
275 std::vector<TabNavigation>* navigations,
276 int index);
277
278 // Does the following:
279 // . Deletes and removes any windows with no tabs or windows with types other
280 // than tabbed_browser or browser. NOTE: constrained windows that have
281 // been dragged out are of type browser. As such, this preserves any dragged
282 // out constrained windows (aka popups that have been dragged out).
283 // . Sorts the tabs in windows with valid tabs based on the tabs
284 // visual order, and adds the valid windows to windows.
285 void SortTabsBasedOnVisualOrderAndPrune(
[email protected]23da84e152010-07-14 01:29:05286 std::map<int, SessionWindow*>* windows,
initial.commit09911bf2008-07-26 23:55:29287 std::vector<SessionWindow*>* valid_windows);
288
289 // Adds tabs to their parent window based on the tab's window_id. This
290 // ignores tabs with no navigations.
[email protected]23da84e152010-07-14 01:29:05291 void AddTabsToWindows(std::map<int, SessionTab*>* tabs,
292 std::map<int, SessionWindow*>* windows);
initial.commit09911bf2008-07-26 23:55:29293
294 // Creates tabs and windows from the specified commands. The created tabs
295 // and windows are added to |tabs| and |windows| respectively. It is up to
296 // the caller to delete the tabs and windows added to |tabs| and |windows|.
297 //
298 // This does NOT add any created SessionTabs to SessionWindow.tabs, that is
299 // done by AddTabsToWindows.
300 bool CreateTabsAndWindows(const std::vector<SessionCommand*>& data,
[email protected]23da84e152010-07-14 01:29:05301 std::map<int, SessionTab*>* tabs,
302 std::map<int, SessionWindow*>* windows);
initial.commit09911bf2008-07-26 23:55:29303
304 // Adds commands to commands that will recreate the state of the specified
[email protected]81898992011-06-14 22:15:00305 // tab. This adds at most kMaxNavigationCountToPersist navigations (in each
306 // direction from the current navigation index).
initial.commit09911bf2008-07-26 23:55:29307 // A pair is added to tab_to_available_range indicating the range of
308 // indices that were written.
309 void BuildCommandsForTab(
310 const SessionID& window_id,
[email protected]81898992011-06-14 22:15:00311 TabContentsWrapper* tab,
initial.commit09911bf2008-07-26 23:55:29312 int index_in_window,
[email protected]5c0e6482009-07-14 20:20:09313 bool is_pinned,
initial.commit09911bf2008-07-26 23:55:29314 std::vector<SessionCommand*>* commands,
315 IdToRange* tab_to_available_range);
316
317 // Adds commands to create the specified browser, and invokes
318 // BuildCommandsForTab for each of the tabs in the browser. This ignores
319 // any tabs not in the profile we were created with.
320 void BuildCommandsForBrowser(
321 Browser* browser,
322 std::vector<SessionCommand*>* commands,
323 IdToRange* tab_to_available_range,
324 std::set<SessionID::id_type>* windows_to_track);
325
326 // Iterates over all the known browsers invoking BuildCommandsForBrowser.
327 // This only adds browsers that should be tracked
328 // (should_track_changes_for_browser_type returns true). All browsers that
329 // are tracked are added to windows_to_track (as long as it is non-null).
330 void BuildCommandsFromBrowsers(
331 std::vector<SessionCommand*>* commands,
332 IdToRange* tab_to_available_range,
333 std::set<SessionID::id_type>* windows_to_track);
334
335 // Schedules a reset. A reset means the contents of the file are recreated
336 // from the state of the browser.
337 void ScheduleReset();
338
339 // Searches for a pending command that can be replaced with command.
340 // If one is found, pending command is removed, command is added to
341 // the pending commands and true is returned.
342 bool ReplacePendingCommand(SessionCommand* command);
343
344 // Schedules the specified command. This method takes ownership of the
345 // command.
[email protected]78994ab02010-12-08 18:06:44346 virtual void ScheduleCommand(SessionCommand* command);
initial.commit09911bf2008-07-26 23:55:29347
348 // Converts all pending tab/window closes to commands and schedules them.
349 void CommitPendingCloses();
350
initial.commit09911bf2008-07-26 23:55:29351 // Returns true if there is only one window open with a single tab that shares
352 // our profile.
353 bool IsOnlyOneTabLeft();
354
[email protected]982921f12009-10-27 21:43:53355 // Returns true if there are open trackable browser windows whose ids do
356 // match |window_id| with our profile. A trackable window is a window from
357 // which |should_track_changes_for_browser_type| returns true. See
358 // |should_track_changes_for_browser_type| for details.
359 bool HasOpenTrackableBrowsers(const SessionID& window_id);
initial.commit09911bf2008-07-26 23:55:29360
361 // Returns true if changes to tabs in the specified window should be tracked.
362 bool ShouldTrackChangesToWindow(const SessionID& window_id);
363
364 // Returns true if we track changes to the specified browser type.
[email protected]b35b26b32011-05-05 20:35:14365 static bool should_track_changes_for_browser_type(Browser::Type type);
initial.commit09911bf2008-07-26 23:55:29366
[email protected]4070a6b2009-11-05 23:33:55367 // Returns true if we should record a window close as pending.
368 // |has_open_trackable_browsers_| must be up-to-date before calling this.
369 bool should_record_close_as_pending() const {
370 // When this is called, the browser window being closed is still open, hence
371 // still in the browser list. If there is a browser window other than the
372 // one being closed but no trackable windows, then the others must be App
373 // windows or similar. In this case, we record the close as pending.
374 return !has_open_trackable_browsers_ &&
375 (!browser_defaults::kBrowserAliveWithNoWindows ||
376 BrowserList::size() > 1);
[email protected]70eb8ed92010-06-10 18:13:12377 }
378
[email protected]23da84e152010-07-14 01:29:05379 // Call when certain session relevant notifications
380 // (tab_closed, nav_list_pruned) occur. In addition, this is
381 // currently called when Save() is called to compare how often the
382 // session data is currently saved verses when we may want to save it.
383 // It records the data in UMA stats.
[email protected]432115822011-07-10 15:52:27384 void RecordSessionUpdateHistogramData(int type,
[email protected]23da84e152010-07-14 01:29:05385 base::TimeTicks* last_updated_time);
386
387 // Helper methods to record the histogram data
388 void RecordUpdatedTabClosed(base::TimeDelta delta, bool use_long_period);
389 void RecordUpdatedNavListPruned(base::TimeDelta delta, bool use_long_period);
390 void RecordUpdatedNavEntryCommit(base::TimeDelta delta, bool use_long_period);
391 void RecordUpdatedSaveTime(base::TimeDelta delta, bool use_long_period);
392 void RecordUpdatedSessionNavigationOrTab(base::TimeDelta delta,
393 bool use_long_period);
[email protected]4070a6b2009-11-05 23:33:55394
[email protected]97d2c1e2009-11-05 03:55:05395 // Convert back/forward between the Browser and SessionService DB window
396 // types.
397 static WindowType WindowTypeForBrowserType(Browser::Type type);
398 static Browser::Type BrowserTypeForWindowType(WindowType type);
399
[email protected]6a02963e2009-01-06 16:58:03400 NotificationRegistrar registrar_;
401
initial.commit09911bf2008-07-26 23:55:29402 // Maps from session tab id to the range of navigation entries that has
403 // been written to disk.
404 //
405 // This is only used if not all the navigation entries have been
406 // written.
407 IdToRange tab_to_available_range_;
408
[email protected]6ea265a2008-10-30 02:58:36409 // When the user closes the last window, where the last window is the
initial.commit09911bf2008-07-26 23:55:29410 // last tabbed browser and no more tabbed browsers are open with the same
411 // profile, the window ID is added here. These IDs are only committed (which
412 // marks them as closed) if the user creates a new tabbed browser.
413 typedef std::set<SessionID::id_type> PendingWindowCloseIDs;
414 PendingWindowCloseIDs pending_window_close_ids_;
415
416 // Set of tabs that have been closed by way of the last window or last tab
417 // closing, but not yet committed.
418 typedef std::set<SessionID::id_type> PendingTabCloseIDs;
419 PendingTabCloseIDs pending_tab_close_ids_;
420
421 // When a window other than the last window (see description of
422 // pending_window_close_ids) is closed, the id is added to this set.
423 typedef std::set<SessionID::id_type> WindowClosingIDs;
424 WindowClosingIDs window_closing_ids_;
425
426 // Set of windows we're tracking changes to. This is only browsers that
427 // return true from should_track_changes_for_browser_type.
428 typedef std::set<SessionID::id_type> WindowsTracking;
429 WindowsTracking windows_tracking_;
430
[email protected]982921f12009-10-27 21:43:53431 // Are there any open trackable browsers?
432 bool has_open_trackable_browsers_;
initial.commit09911bf2008-07-26 23:55:29433
[email protected]6ea265a2008-10-30 02:58:36434 // If true and a new tabbed browser is created and there are no opened tabbed
[email protected]982921f12009-10-27 21:43:53435 // browser (has_open_trackable_browsers_ is false), then the current session
[email protected]668cd422011-04-06 21:00:01436 // is made the last session. See description above class for details on
437 // current/last session.
[email protected]6ea265a2008-10-30 02:58:36438 bool move_on_new_browser_;
[email protected]169627b2008-12-06 19:30:19439
[email protected]47db9a92011-01-24 20:10:13440 // Used for reporting frequency of session altering operations.
[email protected]23da84e152010-07-14 01:29:05441 base::TimeTicks last_updated_tab_closed_time_;
442 base::TimeTicks last_updated_nav_list_pruned_time_;
443 base::TimeTicks last_updated_nav_entry_commit_time_;
444 base::TimeTicks last_updated_save_time_;
445
446 // Constants used in calculating histogram data.
447 const base::TimeDelta save_delay_in_millis_;
448 const base::TimeDelta save_delay_in_mins_;
449 const base::TimeDelta save_delay_in_hrs_;
[email protected]70eb8ed92010-06-10 18:13:12450
[email protected]169627b2008-12-06 19:30:19451 DISALLOW_COPY_AND_ASSIGN(SessionService);
initial.commit09911bf2008-07-26 23:55:29452};
453
[email protected]169627b2008-12-06 19:30:19454#endif // CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_