1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sessions/session_service.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <algorithm>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <limits>
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <set>
1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <vector>
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_vector.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
15731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/pickle.h"
173f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_tab_helper.h"
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/session_startup_pref.h"
2021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sessions/session_backend.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sessions/session_command.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sessions/session_restore.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sessions/session_types.h"
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/tabs/tab_strip_model.h"
264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser_init.h"
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_list.h"
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_window.h"
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h"
31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_controller.h"
32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_entry.h"
33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h"
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX)
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/app_controller_cppsafe_mac.h"
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Identifier for commands written to file.
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandSetTabWindow = 0;
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// kCommandSetWindowBounds is no longer used (it's superseded by
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// kCommandSetWindowBounds2). I leave it here to document what it was.
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static const SessionCommand::id_type kCommandSetWindowBounds = 1;
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandSetTabIndexInWindow = 2;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandTabClosed = 3;
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandWindowClosed = 4;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    kCommandTabNavigationPathPrunedFromBack = 5;
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandUpdateTabNavigation = 6;
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandSetSelectedNavigationIndex = 7;
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandSetSelectedTabInIndex = 8;
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandSetWindowType = 9;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandSetWindowBounds2 = 10;
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    kCommandTabNavigationPathPrunedFromFront = 11;
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandSetPinnedState = 12;
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandSetExtensionAppID = 13;
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Every kWritesPerReset commands triggers recreating the file.
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kWritesPerReset = 250;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The callback from GetLastSession is internally routed to SessionService
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// first and then the caller. This is done so that the SessionWindows can be
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// recreated from the SessionCommands and the SessionWindows passed to the
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// caller. The following class is used for this.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass InternalSessionRequest
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public BaseSessionService::InternalGetCommandsRequest {
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  InternalSessionRequest(
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CallbackType* callback,
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SessionService::SessionCallback* real_callback)
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : BaseSessionService::InternalGetCommandsRequest(callback),
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        real_callback(real_callback) {
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The callback supplied to GetLastSession and GetCurrentSession.
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SessionService::SessionCallback> real_callback;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~InternalSessionRequest() {}
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(InternalSessionRequest);
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Various payload structures.
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct ClosedPayload {
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionID::id_type id;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 close_time;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct WindowBoundsPayload2 {
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionID::id_type window_id;
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int32 x;
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int32 y;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int32 w;
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int32 h;
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool is_maximized;
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct IDAndIndexPayload {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionID::id_type id;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int32 index;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef IDAndIndexPayload TabIndexInWindowPayload;
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef IDAndIndexPayload TabNavigationPathPrunedFromBackPayload;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef IDAndIndexPayload SelectedNavigationIndexPayload;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef IDAndIndexPayload SelectedTabInIndexPayload;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef IDAndIndexPayload WindowTypePayload;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef IDAndIndexPayload TabNavigationPathPrunedFromFrontPayload;
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct PinnedStatePayload {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionID::id_type tab_id;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool pinned_state;
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// SessionService -------------------------------------------------------------
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionService::SessionService(Profile* profile)
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : BaseSessionService(SESSION_RESTORE, profile, FilePath()),
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      has_open_trackable_browsers_(false),
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      move_on_new_browser_(false),
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_hrs_(base::TimeDelta::FromHours(8)) {
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Init();
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionService::SessionService(const FilePath& save_path)
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : BaseSessionService(SESSION_RESTORE, NULL, save_path),
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      has_open_trackable_browsers_(false),
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      move_on_new_browser_(false),
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_hrs_(base::TimeDelta::FromHours(8)) {
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Init();
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionService::~SessionService() {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Save();
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open) {
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return RestoreIfNecessary(urls_to_open, NULL);
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::ResetFromCurrentBrowsers() {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleReset();
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::MoveCurrentSessionToLastSession() {
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pending_tab_close_ids_.clear();
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  window_closing_ids_.clear();
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pending_window_close_ids_.clear();
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Save();
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!backend_thread()) {
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    backend()->MoveCurrentSessionToLastSession();
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    backend_thread()->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        backend(), &SessionBackend::MoveCurrentSessionToLastSession));
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::SetTabWindow(const SessionID& window_id,
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const SessionID& tab_id) {
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(CreateSetTabWindowCommand(window_id, tab_id));
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::SetWindowBounds(const SessionID& window_id,
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     const gfx::Rect& bounds,
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     bool is_maximized) {
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(CreateSetWindowBoundsCommand(window_id, bounds,
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               is_maximized));
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::SetTabIndexInWindow(const SessionID& window_id,
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         const SessionID& tab_id,
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         int new_index) {
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(CreateSetTabIndexInWindowCommand(tab_id, new_index));
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::SetPinnedState(const SessionID& window_id,
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    const SessionID& tab_id,
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    bool is_pinned) {
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(CreatePinnedStateCommand(tab_id, is_pinned));
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::TabClosed(const SessionID& window_id,
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               const SessionID& tab_id,
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               bool closed_by_user_gesture) {
218731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!tab_id.id())
219731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;  // Hapens when the tab is replaced.
220731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  IdToRange::iterator i = tab_to_available_range_.find(tab_id.id());
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (i != tab_to_available_range_.end())
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_to_available_range_.erase(i);
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (find(pending_window_close_ids_.begin(), pending_window_close_ids_.end(),
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           window_id.id()) != pending_window_close_ids_.end()) {
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Tab is in last window. Don't commit it immediately, instead add it to the
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // list of tabs to close. If the user creates another window, the close is
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // committed.
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    pending_tab_close_ids_.insert(tab_id.id());
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (find(window_closing_ids_.begin(), window_closing_ids_.end(),
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  window_id.id()) != window_closing_ids_.end() ||
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             !IsOnlyOneTabLeft() ||
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             closed_by_user_gesture) {
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Close is the result of one of the following:
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // . window close (and it isn't the last window).
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // . closing a tab and there are other windows/tabs open.
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // . closed by a user gesture.
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // In all cases we need to mark the tab as explicitly closed.
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScheduleCommand(CreateTabClosedCommand(tab_id.id()));
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // User closed the last tab in the last tabbed browser. Don't mark the
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // tab closed.
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    pending_tab_close_ids_.insert(tab_id.id());
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    has_open_trackable_browsers_ = false;
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::WindowClosing(const SessionID& window_id) {
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The window is about to close. If there are other tabbed browsers with the
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // same original profile commit the close immediately.
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NOTE: if the user chooses the exit menu item session service is destroyed
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and this code isn't hit.
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (has_open_trackable_browsers_) {
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Closing a window can never make has_open_trackable_browsers_ go from
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // false to true, so only update it if already true.
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    has_open_trackable_browsers_ = HasOpenTrackableBrowsers(window_id);
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (should_record_close_as_pending())
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    pending_window_close_ids_.insert(window_id.id());
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    window_closing_ids_.insert(window_id.id());
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::WindowClosed(const SessionID& window_id) {
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  windows_tracking_.erase(window_id.id());
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (window_closing_ids_.find(window_id.id()) != window_closing_ids_.end()) {
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    window_closing_ids_.erase(window_id.id());
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScheduleCommand(CreateWindowClosedCommand(window_id.id()));
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (pending_window_close_ids_.find(window_id.id()) ==
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             pending_window_close_ids_.end()) {
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We'll hit this if user closed the last tab in a window.
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    has_open_trackable_browsers_ = HasOpenTrackableBrowsers(window_id);
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (should_record_close_as_pending())
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      pending_window_close_ids_.insert(window_id.id());
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ScheduleCommand(CreateWindowClosedCommand(window_id.id()));
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::SetWindowType(const SessionID& window_id,
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   Browser::Type type) {
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!should_track_changes_for_browser_type(type))
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  windows_tracking_.insert(window_id.id());
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The user created a new tabbed browser with our profile. Commit any
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // pending closes.
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CommitPendingCloses();
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  has_open_trackable_browsers_ = true;
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  move_on_new_browser_ = true;
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CreateSetWindowTypeCommand(window_id, WindowTypeForBrowserType(type)));
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::TabNavigationPathPrunedFromBack(const SessionID& window_id,
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     const SessionID& tab_id,
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     int count) {
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabNavigationPathPrunedFromBackPayload payload = { 0 };
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.id = tab_id.id();
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.index = count;
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command =
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new SessionCommand(kCommandTabNavigationPathPrunedFromBack,
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         sizeof(payload));
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), &payload, sizeof(payload));
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(command);
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::TabNavigationPathPrunedFromFront(
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& window_id,
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& tab_id,
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int count) {
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update the range of indices.
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab_to_available_range_.find(tab_id.id()) !=
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_to_available_range_.end()) {
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::pair<int, int>& range = tab_to_available_range_[tab_id.id()];
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    range.first = std::max(0, range.first - count);
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    range.second = std::max(0, range.second - count);
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabNavigationPathPrunedFromFrontPayload payload = { 0 };
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.id = tab_id.id();
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.index = count;
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command =
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new SessionCommand(kCommandTabNavigationPathPrunedFromFront,
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         sizeof(payload));
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), &payload, sizeof(payload));
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(command);
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::UpdateTabNavigation(const SessionID& window_id,
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         const SessionID& tab_id,
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         int index,
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         const NavigationEntry& entry) {
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackEntry(entry) || !ShouldTrackChangesToWindow(window_id))
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab_to_available_range_.find(tab_id.id()) !=
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_to_available_range_.end()) {
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::pair<int, int>& range = tab_to_available_range_[tab_id.id()];
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    range.first = std::min(index, range.first);
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    range.second = std::max(index, range.second);
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation,
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   tab_id.id(), index, entry));
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::TabRestored(NavigationController* controller,
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 bool pinned) {
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(controller->window_id()))
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BuildCommandsForTab(controller->window_id(), controller, -1,
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      pinned, &pending_commands(), NULL);
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartSaveTimer();
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::SetSelectedNavigationIndex(const SessionID& window_id,
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                const SessionID& tab_id,
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                int index) {
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab_to_available_range_.find(tab_id.id()) !=
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_to_available_range_.end()) {
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (index < tab_to_available_range_[tab_id.id()].first ||
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        index > tab_to_available_range_[tab_id.id()].second) {
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The new index is outside the range of what we've archived, schedule
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // a reset.
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ResetFromCurrentBrowsers();
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(CreateSetSelectedNavigationIndexCommand(tab_id, index));
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::SetSelectedTabInWindow(const SessionID& window_id,
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            int index) {
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(CreateSetSelectedTabInWindow(window_id, index));
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionService::Handle SessionService::GetLastSession(
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CancelableRequestConsumerBase* consumer,
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SessionCallback* callback) {
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ScheduleGetLastSessionCommands(
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new InternalSessionRequest(
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NewCallback(this, &SessionService::OnGotSessionCommands),
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          callback), consumer);
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionService::Handle SessionService::GetCurrentSession(
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CancelableRequestConsumerBase* consumer,
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SessionCallback* callback) {
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (pending_window_close_ids_.empty()) {
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If there are no pending window closes, we can get the current session
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // from memory.
420513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    scoped_refptr<InternalSessionRequest> request(new InternalSessionRequest(
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NewCallback(this, &SessionService::OnGotSessionCommands),
422513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        callback));
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddRequest(request, consumer);
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IdToRange tab_to_available_range;
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::set<SessionID::id_type> windows_to_track;
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BuildCommandsFromBrowsers(&(request->commands),
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              &tab_to_available_range,
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              &windows_to_track);
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    request->ForwardResult(
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        BaseSessionService::InternalGetCommandsRequest::TupleType(
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            request->handle(), request));
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return request->handle();
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If there are pending window closes, read the current session from disk.
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ScheduleGetCurrentSessionCommands(
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new InternalSessionRequest(
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            NewCallback(this, &SessionService::OnGotSessionCommands),
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            callback), consumer);
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::Save() {
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool had_commands = !pending_commands().empty();
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseSessionService::Save();
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (had_commands) {
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    RecordSessionUpdateHistogramData(NotificationType::SESSION_SERVICE_SAVED,
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &last_updated_save_time_);
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NotificationService::current()->Notify(
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NotificationType::SESSION_SERVICE_SAVED,
450731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        Source<Profile>(profile()),
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NotificationService::NoDetails());
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::Init() {
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Register for the notifications we're interested in.
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::TAB_PARENTED,
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::TAB_CLOSED,
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::NAV_LIST_PRUNED,
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::NAV_ENTRY_CHANGED,
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::BROWSER_OPENED,
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this,
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open,
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        Browser* browser) {
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!has_open_trackable_browsers_ && !BrowserInit::InProcessStartup() &&
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !SessionRestore::IsRestoring()
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX)
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // OSX has a fairly different idea of application lifetime than the
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // other platforms. We need to check that we aren't opening a window
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // from the dock or the menubar.
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      && !app_controller_mac::IsOpeningNewWindow()
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ) {
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We're going from no tabbed browsers to a tabbed browser (and not in
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // process startup), restore the last session.
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (move_on_new_browser_) {
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Make the current session the last.
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MoveCurrentSessionToLastSession();
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      move_on_new_browser_ = false;
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SessionStartupPref pref = SessionStartupPref::GetStartupPref(profile());
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (pref.type == SessionStartupPref::LAST) {
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SessionRestore::RestoreSession(
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          profile(), browser, false, browser ? false : true, urls_to_open);
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::Observe(NotificationType type,
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             const NotificationSource& source,
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             const NotificationDetails& details) {
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // All of our messages have the NavigationController as the source.
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (type.value) {
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NotificationType::BROWSER_OPENED: {
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Browser* browser = Source<Browser>(source).ptr();
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (browser->profile() != profile() ||
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          !should_track_changes_for_browser_type(browser->type())) {
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return;
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      RestoreIfNecessary(std::vector<GURL>(), browser);
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SetWindowType(browser->session_id(), browser->type());
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NotificationType::TAB_PARENTED: {
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NavigationController* controller =
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          Source<NavigationController>(source).ptr();
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SetTabWindow(controller->window_id(), controller->session_id());
523ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      TabContentsWrapper* wrapper =
524ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          TabContentsWrapper::GetCurrentWrapperForContents(
525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              controller->tab_contents());
526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (wrapper->extension_tab_helper()->extension_app()) {
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SetTabExtensionAppID(
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            controller->window_id(),
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            controller->session_id(),
530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            wrapper->extension_tab_helper()->extension_app()->id());
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NotificationType::TAB_CLOSED: {
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NavigationController* controller =
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          Source<NavigationController>(source).ptr();
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      TabClosed(controller->window_id(), controller->session_id(),
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                controller->tab_contents()->closed_by_user_gesture());
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      RecordSessionUpdateHistogramData(NotificationType::TAB_CLOSED,
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &last_updated_tab_closed_time_);
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NotificationType::NAV_LIST_PRUNED: {
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NavigationController* controller =
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          Source<NavigationController>(source).ptr();
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Details<NavigationController::PrunedDetails> pruned_details(details);
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (pruned_details->from_front) {
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        TabNavigationPathPrunedFromFront(controller->window_id(),
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         controller->session_id(),
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         pruned_details->count);
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        TabNavigationPathPrunedFromBack(controller->window_id(),
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        controller->session_id(),
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        controller->entry_count());
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      RecordSessionUpdateHistogramData(NotificationType::NAV_LIST_PRUNED,
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &last_updated_nav_list_pruned_time_);
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NotificationType::NAV_ENTRY_CHANGED: {
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NavigationController* controller =
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          Source<NavigationController>(source).ptr();
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Details<NavigationController::EntryChangedDetails> changed(details);
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UpdateTabNavigation(controller->window_id(), controller->session_id(),
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          changed->index, *changed->changed_entry);
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NotificationType::NAV_ENTRY_COMMITTED: {
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NavigationController* controller =
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          Source<NavigationController>(source).ptr();
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int current_entry_index = controller->GetCurrentEntryIndex();
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SetSelectedNavigationIndex(controller->window_id(),
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 controller->session_id(),
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 current_entry_index);
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UpdateTabNavigation(controller->window_id(), controller->session_id(),
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          current_entry_index,
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          *controller->GetEntryAtIndex(current_entry_index));
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Details<NavigationController::LoadCommittedDetails> changed(details);
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (changed->type == NavigationType::NEW_PAGE ||
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        changed->type == NavigationType::EXISTING_PAGE) {
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RecordSessionUpdateHistogramData(NotificationType::NAV_ENTRY_COMMITTED,
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            &last_updated_nav_entry_commit_time_);
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED: {
592ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ExtensionTabHelper* extension_tab_helper =
593ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          Source<ExtensionTabHelper>(source).ptr();
594ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (extension_tab_helper->extension_app()) {
595ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        SetTabExtensionAppID(
596ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            extension_tab_helper->tab_contents()->controller().window_id(),
597ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            extension_tab_helper->tab_contents()->controller().session_id(),
598ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            extension_tab_helper->extension_app()->id());
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::SetTabExtensionAppID(
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& window_id,
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& tab_id,
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& extension_app_id) {
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldTrackChangesToWindow(window_id))
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleCommand(CreateSetTabExtensionAppIDCommand(
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      kCommandSetExtensionAppID,
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      tab_id.id(),
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      extension_app_id));
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* SessionService::CreateSetSelectedTabInWindow(
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& window_id,
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int index) {
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SelectedTabInIndexPayload payload = { 0 };
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.id = window_id.id();
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.index = index;
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command = new SessionCommand(kCommandSetSelectedTabInIndex,
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 sizeof(payload));
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), &payload, sizeof(payload));
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return command;
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* SessionService::CreateSetTabWindowCommand(
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& window_id,
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& tab_id) {
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionID::id_type payload[] = { window_id.id(), tab_id.id() };
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command =
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new SessionCommand(kCommandSetTabWindow, sizeof(payload));
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), payload, sizeof(payload));
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return command;
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* SessionService::CreateSetWindowBoundsCommand(
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& window_id,
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const gfx::Rect& bounds,
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool is_maximized) {
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WindowBoundsPayload2 payload = { 0 };
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.window_id = window_id.id();
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.x = bounds.x();
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.y = bounds.y();
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.w = bounds.width();
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.h = bounds.height();
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.is_maximized = is_maximized;
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command = new SessionCommand(kCommandSetWindowBounds2,
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               sizeof(payload));
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), &payload, sizeof(payload));
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return command;
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* SessionService::CreateSetTabIndexInWindowCommand(
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& tab_id,
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int new_index) {
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabIndexInWindowPayload payload = { 0 };
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.id = tab_id.id();
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.index = new_index;
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command =
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new SessionCommand(kCommandSetTabIndexInWindow, sizeof(payload));
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), &payload, sizeof(payload));
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return command;
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* SessionService::CreateTabClosedCommand(
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID::id_type tab_id) {
674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClosedPayload payload;
675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Because of what appears to be a compiler bug setting payload to {0} doesn't
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // set the padding to 0, resulting in Purify reporting an UMR when we write
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the structure to disk. To avoid this we explicitly memset the struct.
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memset(&payload, 0, sizeof(payload));
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.id = tab_id;
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.close_time = Time::Now().ToInternalValue();
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command =
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new SessionCommand(kCommandTabClosed, sizeof(payload));
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), &payload, sizeof(payload));
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return command;
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* SessionService::CreateWindowClosedCommand(
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID::id_type window_id) {
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClosedPayload payload;
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See comment in CreateTabClosedCommand as to why we do this.
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memset(&payload, 0, sizeof(payload));
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.id = window_id;
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.close_time = Time::Now().ToInternalValue();
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command =
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new SessionCommand(kCommandWindowClosed, sizeof(payload));
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), &payload, sizeof(payload));
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return command;
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* SessionService::CreateSetSelectedNavigationIndexCommand(
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& tab_id,
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int index) {
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SelectedNavigationIndexPayload payload = { 0 };
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.id = tab_id.id();
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.index = index;
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command = new SessionCommand(
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kCommandSetSelectedNavigationIndex, sizeof(payload));
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), &payload, sizeof(payload));
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return command;
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* SessionService::CreateSetWindowTypeCommand(
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& window_id,
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WindowType type) {
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WindowTypePayload payload = { 0 };
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.id = window_id.id();
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.index = static_cast<int32>(type);
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command = new SessionCommand(
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kCommandSetWindowType, sizeof(payload));
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), &payload, sizeof(payload));
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return command;
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* SessionService::CreatePinnedStateCommand(
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& tab_id,
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool is_pinned) {
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PinnedStatePayload payload = { 0 };
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.tab_id = tab_id.id();
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  payload.pinned_state = is_pinned;
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionCommand* command =
731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new SessionCommand(kCommandSetPinnedState, sizeof(payload));
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(command->contents(), &payload, sizeof(payload));
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return command;
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::OnGotSessionCommands(
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Handle handle,
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_refptr<InternalGetCommandsRequest> request) {
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->canceled())
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedVector<SessionWindow> valid_windows;
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RestoreSessionFromCommands(
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      request->commands, &(valid_windows.get()));
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static_cast<InternalSessionRequest*>(request.get())->
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      real_callback->RunWithParams(
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          SessionCallback::TupleType(request->handle(),
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     &(valid_windows.get())));
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::RestoreSessionFromCommands(
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<SessionCommand*>& commands,
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<SessionWindow*>* valid_windows) {
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<int, SessionTab*> tabs;
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<int, SessionWindow*> windows;
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (CreateTabsAndWindows(commands, &tabs, &windows)) {
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddTabsToWindows(&tabs, &windows);
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SortTabsBasedOnVisualOrderAndPrune(&windows, valid_windows);
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UpdateSelectedTabIndex(valid_windows);
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  STLDeleteValues(&tabs);
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't delete conents of windows, that is done by the caller as all
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // valid windows are added to valid_windows.
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::UpdateSelectedTabIndex(
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<SessionWindow*>* windows) {
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<SessionWindow*>::const_iterator i = windows->begin();
769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != windows->end(); ++i) {
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See note in SessionWindow as to why we do this.
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int new_index = 0;
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (std::vector<SessionTab*>::const_iterator j = (*i)->tabs.begin();
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         j != (*i)->tabs.end(); ++j) {
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if ((*j)->tab_visual_index == (*i)->selected_tab_index) {
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_index = static_cast<int>(j - (*i)->tabs.begin());
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*i)->selected_tab_index = new_index;
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionWindow* SessionService::GetWindow(
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SessionID::id_type window_id,
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IdToSessionWindow* windows) {
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<int, SessionWindow*>::iterator i = windows->find(window_id);
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (i == windows->end()) {
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SessionWindow* window = new SessionWindow();
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    window->window_id.set_id(window_id);
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*windows)[window_id] = window;
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return window;
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return i->second;
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionTab* SessionService::GetTab(
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SessionID::id_type tab_id,
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IdToSessionTab* tabs) {
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(tabs);
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<int, SessionTab*>::iterator i = tabs->find(tab_id);
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (i == tabs->end()) {
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SessionTab* tab = new SessionTab();
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab->tab_id.set_id(tab_id);
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*tabs)[tab_id] = tab;
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return tab;
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return i->second;
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::vector<TabNavigation>::iterator
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionService::FindClosestNavigationWithIndex(
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<TabNavigation>* navigations,
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int index) {
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(navigations);
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<TabNavigation>::iterator i = navigations->begin();
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != navigations->end(); ++i) {
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (i->index() >= index)
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return i;
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return navigations->end();
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Function used in sorting windows. Sorting is done based on window id. As
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// window ids increment for each new window, this effectively sorts by creation
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// time.
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool WindowOrderSortFunction(const SessionWindow* w1,
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    const SessionWindow* w2) {
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return w1->window_id.id() < w2->window_id.id();
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Compares the two tabs based on visual index.
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool TabVisualIndexSortFunction(const SessionTab* t1,
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       const SessionTab* t2) {
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int delta = t1->tab_visual_index - t2->tab_visual_index;
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return delta == 0 ? (t1->tab_id.id() < t2->tab_id.id()) : (delta < 0);
836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::SortTabsBasedOnVisualOrderAndPrune(
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::map<int, SessionWindow*>* windows,
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<SessionWindow*>* valid_windows) {
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<int, SessionWindow*>::iterator i = windows->begin();
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (i != windows->end()) {
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (i->second->tabs.empty() || i->second->is_constrained ||
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !should_track_changes_for_browser_type(
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            static_cast<Browser::Type>(i->second->type))) {
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delete i->second;
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      windows->erase(i++);
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Valid window; sort the tabs and add it to the list of valid windows.
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::sort(i->second->tabs.begin(), i->second->tabs.end(),
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                &TabVisualIndexSortFunction);
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Add the window such that older windows appear first.
853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (valid_windows->empty()) {
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        valid_windows->push_back(i->second);
855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        valid_windows->insert(
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            std::upper_bound(valid_windows->begin(), valid_windows->end(),
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             i->second, &WindowOrderSortFunction),
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            i->second);
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++i;
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::AddTabsToWindows(std::map<int, SessionTab*>* tabs,
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      std::map<int, SessionWindow*>* windows) {
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<int, SessionTab*>::iterator i = tabs->begin();
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (i != tabs->end()) {
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SessionTab* tab = i->second;
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab->window_id.id() && !tab->navigations.empty()) {
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SessionWindow* window = GetWindow(tab->window_id.id(), windows);
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      window->tabs.push_back(tab);
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tabs->erase(i++);
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // See note in SessionTab as to why we do this.
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::vector<TabNavigation>::iterator j =
878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          FindClosestNavigationWithIndex(&(tab->navigations),
879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         tab->current_navigation_index);
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (j == tab->navigations.end()) {
881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab->current_navigation_index =
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            static_cast<int>(tab->navigations.size() - 1);
883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab->current_navigation_index =
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            static_cast<int>(j - tab->navigations.begin());
886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Never got a set tab index in window, or tabs are empty, nothing
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // to do.
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++i;
891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SessionService::CreateTabsAndWindows(
896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<SessionCommand*>& data,
897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::map<int, SessionTab*>* tabs,
898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::map<int, SessionWindow*>* windows) {
899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the file is corrupt (command with wrong size, or unknown command), we
900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // still return true and attempt to restore what we we can.
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<SessionCommand*>::const_iterator i = data.begin();
903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != data.end(); ++i) {
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionCommand* command = *i;
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (command->id()) {
907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandSetTabWindow: {
908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SessionID::id_type payload[2];
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!command->GetPayload(payload, sizeof(payload)))
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetTab(payload[1], tabs)->window_id.set_id(payload[0]);
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandSetWindowBounds2: {
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        WindowBoundsPayload2 payload;
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!command->GetPayload(&payload, sizeof(payload)))
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetWindow(payload.window_id, windows)->bounds.SetRect(payload.x,
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                              payload.y,
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                              payload.w,
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                              payload.h);
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetWindow(payload.window_id, windows)->is_maximized =
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            payload.is_maximized;
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandSetTabIndexInWindow: {
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        TabIndexInWindowPayload payload;
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!command->GetPayload(&payload, sizeof(payload)))
931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetTab(payload.id, tabs)->tab_visual_index = payload.index;
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandTabClosed:
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandWindowClosed: {
938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ClosedPayload payload;
939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!command->GetPayload(&payload, sizeof(payload)))
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (command->id() == kCommandTabClosed) {
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          delete GetTab(payload.id, tabs);
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          tabs->erase(payload.id);
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        } else {
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          delete GetWindow(payload.id, windows);
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          windows->erase(payload.id);
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandTabNavigationPathPrunedFromBack: {
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        TabNavigationPathPrunedFromBackPayload payload;
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!command->GetPayload(&payload, sizeof(payload)))
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SessionTab* tab = GetTab(payload.id, tabs);
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab->navigations.erase(
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            FindClosestNavigationWithIndex(&(tab->navigations), payload.index),
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            tab->navigations.end());
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandTabNavigationPathPrunedFromFront: {
963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        TabNavigationPathPrunedFromFrontPayload payload;
964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!command->GetPayload(&payload, sizeof(payload)) ||
965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            payload.index <= 0) {
966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SessionTab* tab = GetTab(payload.id, tabs);
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Update the selected navigation index.
971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab->current_navigation_index =
972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            std::max(-1, tab->current_navigation_index - payload.index);
973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // And update the index of existing navigations.
975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        for (std::vector<TabNavigation>::iterator i = tab->navigations.begin();
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             i != tab->navigations.end();) {
977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          i->set_index(i->index() - payload.index);
978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (i->index() < 0)
979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            i = tab->navigations.erase(i);
980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          else
981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            ++i;
982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandUpdateTabNavigation: {
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        TabNavigation navigation;
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SessionID::id_type tab_id;
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!RestoreUpdateTabNavigationCommand(*command, &navigation, &tab_id))
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SessionTab* tab = GetTab(tab_id, tabs);
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::vector<TabNavigation>::iterator i =
994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            FindClosestNavigationWithIndex(&(tab->navigations),
995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           navigation.index());
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (i != tab->navigations.end() && i->index() == navigation.index())
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          *i = navigation;
998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        else
999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          tab->navigations.insert(i, navigation);
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandSetSelectedNavigationIndex: {
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SelectedNavigationIndexPayload payload;
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!command->GetPayload(&payload, sizeof(payload)))
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetTab(payload.id, tabs)->current_navigation_index = payload.index;
1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandSetSelectedTabInIndex: {
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SelectedTabInIndexPayload payload;
1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!command->GetPayload(&payload, sizeof(payload)))
1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetWindow(payload.id, windows)->selected_tab_index = payload.index;
1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandSetWindowType: {
1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        WindowTypePayload payload;
1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!command->GetPayload(&payload, sizeof(payload)))
1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetWindow(payload.id, windows)->is_constrained = false;
1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetWindow(payload.id, windows)->type =
1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            BrowserTypeForWindowType(
1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                static_cast<WindowType>(payload.index));
1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandSetPinnedState: {
1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        PinnedStatePayload payload;
1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!command->GetPayload(&payload, sizeof(payload)))
1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetTab(payload.tab_id, tabs)->pinned = payload.pinned_state;
1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case kCommandSetExtensionAppID: {
1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SessionID::id_type tab_id;
1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::string extension_app_id;
1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!RestoreSetTabExtensionAppIDCommand(
1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                *command, &tab_id, &extension_app_id)) {
1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetTab(tab_id, tabs)->extension_app_id.swap(extension_app_id);
1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return true;
1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::BuildCommandsForTab(
1058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID& window_id,
1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NavigationController* controller,
1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int index_in_window,
1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool is_pinned,
1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<SessionCommand*>* commands,
1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IdToRange* tab_to_available_range) {
1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(controller && commands && window_id.id());
1065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  commands->push_back(
1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CreateSetTabWindowCommand(window_id, controller->session_id()));
1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int current_index = controller->GetCurrentEntryIndex();
1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int min_index = std::max(0,
1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 current_index - max_persist_navigation_count);
1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int max_index = std::min(current_index + max_persist_navigation_count,
1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 controller->entry_count());
1072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int pending_index = controller->pending_entry_index();
1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab_to_available_range) {
1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*tab_to_available_range)[controller->session_id().id()] =
1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::pair<int, int>(min_index, max_index);
1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (is_pinned) {
1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    commands->push_back(
1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        CreatePinnedStateCommand(controller->session_id(), true));
1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1081ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TabContentsWrapper* wrapper =
1082ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      TabContentsWrapper::GetCurrentWrapperForContents(
1083ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          controller->tab_contents());
1084ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (wrapper->extension_tab_helper()->extension_app()) {
1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    commands->push_back(
1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        CreateSetTabExtensionAppIDCommand(
1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            kCommandSetExtensionAppID,
1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            controller->session_id().id(),
1089ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            wrapper->extension_tab_helper()->extension_app()->id()));
1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = min_index; i < max_index; ++i) {
1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const NavigationEntry* entry = (i == pending_index) ?
1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        controller->pending_entry() : controller->GetEntryAtIndex(i);
1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(entry);
1095c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (ShouldTrackEntry(*entry)) {
1096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      commands->push_back(
1097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation,
1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           controller->session_id().id(),
1099c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           i,
1100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           *entry));
1101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  commands->push_back(
1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CreateSetSelectedNavigationIndexCommand(controller->session_id(),
1105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              current_index));
1106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index_in_window != -1) {
1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    commands->push_back(
1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        CreateSetTabIndexInWindowCommand(controller->session_id(),
1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         index_in_window));
1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::BuildCommandsForBrowser(
1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Browser* browser,
1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<SessionCommand*>* commands,
1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IdToRange* tab_to_available_range,
1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::set<SessionID::id_type>* windows_to_track) {
1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(browser && commands);
1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(browser->session_id().id());
1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  commands->push_back(
1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CreateSetWindowBoundsCommand(browser->session_id(),
1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   browser->window()->GetRestoredBounds(),
1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   browser->window()->IsMaximized()));
1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  commands->push_back(CreateSetWindowTypeCommand(
1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser->session_id(), WindowTypeForBrowserType(browser->type())));
1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool added_to_windows_to_track = false;
1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < browser->tab_count(); ++i) {
1132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabContents* tab = browser->GetTabContentsAt(i);
1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(tab);
1134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab->profile() == profile() || profile() == NULL) {
1135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BuildCommandsForTab(browser->session_id(), &tab->controller(), i,
1136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          browser->tabstrip_model()->IsTabPinned(i),
1137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          commands, tab_to_available_range);
1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (windows_to_track && !added_to_windows_to_track) {
1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        windows_to_track->insert(browser->session_id().id());
1140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        added_to_windows_to_track = true;
1141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  commands->push_back(
1145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CreateSetSelectedTabInWindow(browser->session_id(),
1146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                   browser->active_index()));
1147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::BuildCommandsFromBrowsers(
1150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<SessionCommand*>* commands,
1151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IdToRange* tab_to_available_range,
1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::set<SessionID::id_type>* windows_to_track) {
1153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(commands);
1154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator i = BrowserList::begin();
1155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != BrowserList::end(); ++i) {
1156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Make sure the browser has tabs and a window. Browsers destructor
1157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // removes itself from the BrowserList. When a browser is closed the
1158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // destructor is not necessarily run immediately. This means its possible
1159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // for us to get a handle to a browser that is about to be removed. If
1160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the tab count is 0 or the window is NULL, the browser is about to be
1161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // deleted, so we ignore it.
1162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (should_track_changes_for_browser_type((*i)->type()) &&
1163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (*i)->tab_count() && (*i)->window()) {
1164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BuildCommandsForBrowser(*i, commands, tab_to_available_range,
1165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              windows_to_track);
1166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::ScheduleReset() {
1171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set_pending_reset(true);
1172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  STLDeleteElements(&pending_commands());
1173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_to_available_range_.clear();
1174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  windows_tracking_.clear();
1175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BuildCommandsFromBrowsers(&pending_commands(), &tab_to_available_range_,
1176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            &windows_tracking_);
1177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!windows_tracking_.empty()) {
1178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We're lazily created on startup and won't get an initial batch of
1179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // SetWindowType messages. Set these here to make sure our state is correct.
1180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    has_open_trackable_browsers_ = true;
1181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    move_on_new_browser_ = true;
1182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartSaveTimer();
1184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SessionService::ReplacePendingCommand(SessionCommand* command) {
1187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We only optimize page navigations, which can happen quite frequently and
1188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // are expensive. If necessary, other commands could be searched for as
1189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // well.
1190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (command->id() != kCommandUpdateTabNavigation)
1191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void* iterator = NULL;
1193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<Pickle> command_pickle(command->PayloadAsPickle());
1194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionID::id_type command_tab_id;
1195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int command_nav_index;
1196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!command_pickle->ReadInt(&iterator, &command_tab_id) ||
1197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !command_pickle->ReadInt(&iterator, &command_nav_index)) {
1198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<SessionCommand*>::reverse_iterator i =
1201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       pending_commands().rbegin(); i != pending_commands().rend(); ++i) {
1202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SessionCommand* existing_command = *i;
1203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (existing_command->id() == kCommandUpdateTabNavigation) {
1204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SessionID::id_type existing_tab_id;
1205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int existing_nav_index;
1206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      {
1207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Creating a pickle like this means the Pickle references the data from
1208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // the command. Make sure we delete the pickle before the command, else
1209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // the pickle references deleted memory.
1210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        scoped_ptr<Pickle> existing_pickle(existing_command->PayloadAsPickle());
1211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        iterator = NULL;
1212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!existing_pickle->ReadInt(&iterator, &existing_tab_id) ||
1213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            !existing_pickle->ReadInt(&iterator, &existing_nav_index)) {
1214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
1215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
1216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (existing_tab_id == command_tab_id &&
1218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          existing_nav_index == command_nav_index) {
1219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // existing_command is an update for the same tab/index pair. Replace
1220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // it with the new one. We need to add to the end of the list just in
1221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // case there is a prune command after the update command.
1222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        delete existing_command;
1223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        pending_commands().erase(i.base() - 1);
1224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        pending_commands().push_back(command);
1225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return true;
1226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
1231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::ScheduleCommand(SessionCommand* command) {
1234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(command);
1235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (ReplacePendingCommand(command))
1236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseSessionService::ScheduleCommand(command);
1238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't schedule a reset on tab closed/window closed. Otherwise we may
1239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // lose tabs/windows we want to restore from if we exit right after this.
1240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!pending_reset() && pending_window_close_ids_.empty() &&
1241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      commands_since_reset() >= kWritesPerReset &&
1242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (command->id() != kCommandTabClosed &&
1243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       command->id() != kCommandWindowClosed)) {
1244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScheduleReset();
1245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::CommitPendingCloses() {
1249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (PendingTabCloseIDs::iterator i = pending_tab_close_ids_.begin();
1250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != pending_tab_close_ids_.end(); ++i) {
1251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScheduleCommand(CreateTabClosedCommand(*i));
1252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pending_tab_close_ids_.clear();
1254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (PendingWindowCloseIDs::iterator i = pending_window_close_ids_.begin();
1256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != pending_window_close_ids_.end(); ++i) {
1257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScheduleCommand(CreateWindowClosedCommand(*i));
1258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pending_window_close_ids_.clear();
1260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SessionService::IsOnlyOneTabLeft() {
1263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!profile()) {
1264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We're testing, always return false.
1265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_count = 0;
1269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator i = BrowserList::begin();
1270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != BrowserList::end(); ++i) {
1271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID::id_type window_id = (*i)->session_id().id();
1272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (should_track_changes_for_browser_type((*i)->type()) &&
1273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        (*i)->profile() == profile() &&
1274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        window_closing_ids_.find(window_id) == window_closing_ids_.end()) {
1275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (++window_count > 1)
1276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
1277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // By the time this is invoked the tab has been removed. As such, we use
1278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // > 0 here rather than > 1.
1279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if ((*i)->tab_count() > 0)
1280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
1281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SessionService::HasOpenTrackableBrowsers(const SessionID& window_id) {
1287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!profile()) {
1288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We're testing, always return false.
1289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
1290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator i = BrowserList::begin();
1293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != BrowserList::end(); ++i) {
1294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Browser* browser = *i;
1295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SessionID::id_type browser_id = browser->session_id().id();
1296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (browser_id != window_id.id() &&
1297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        window_closing_ids_.find(browser_id) == window_closing_ids_.end() &&
1298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        should_track_changes_for_browser_type(browser->type()) &&
1299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        browser->profile() == profile()) {
1300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
1301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
1304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SessionService::ShouldTrackChangesToWindow(const SessionID& window_id) {
1307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return windows_tracking_.find(window_id.id()) != windows_tracking_.end();
1308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1311c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionService::WindowType SessionService::WindowTypeForBrowserType(
1312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Browser::Type type) {
1313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't support masks here, only discrete types.
1314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (type) {
1315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case Browser::TYPE_POPUP:
1316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return TYPE_POPUP;
1317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case Browser::TYPE_APP:
1318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return TYPE_APP;
1319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case Browser::TYPE_APP_POPUP:
1320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return TYPE_APP_POPUP;
1321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case Browser::TYPE_DEVTOOLS:
1322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return TYPE_DEVTOOLS;
1323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case Browser::TYPE_APP_PANEL:
1324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return TYPE_APP_PANEL;
1325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case Browser::TYPE_NORMAL:
1326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
1327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return TYPE_NORMAL;
1328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1331c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowser::Type SessionService::BrowserTypeForWindowType(
1332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SessionService::WindowType type) {
1333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (type) {
1334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case TYPE_POPUP:
1335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return Browser::TYPE_POPUP;
1336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case TYPE_APP:
1337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return Browser::TYPE_APP;
1338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case TYPE_APP_POPUP:
1339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return Browser::TYPE_APP_POPUP;
1340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case TYPE_DEVTOOLS:
1341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return Browser::TYPE_DEVTOOLS;
1342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case TYPE_APP_PANEL:
1343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return Browser::TYPE_APP_PANEL;
1344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case TYPE_NORMAL:
1345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
1346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return Browser::TYPE_NORMAL;
1347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::RecordSessionUpdateHistogramData(NotificationType type,
1351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::TimeTicks* last_updated_time) {
1352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!last_updated_time->is_null()) {
1353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::TimeDelta delta = base::TimeTicks::Now() - *last_updated_time;
1354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We're interested in frequent updates periods longer than
1355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // 10 minutes.
1356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool use_long_period = false;
1357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (delta >= save_delay_in_mins_) {
1358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      use_long_period = true;
1359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (type.value) {
1361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case NotificationType::SESSION_SERVICE_SAVED :
1362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RecordUpdatedSaveTime(delta, use_long_period);
1363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RecordUpdatedSessionNavigationOrTab(delta, use_long_period);
1364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case NotificationType::TAB_CLOSED:
1366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RecordUpdatedTabClosed(delta, use_long_period);
1367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RecordUpdatedSessionNavigationOrTab(delta, use_long_period);
1368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case NotificationType::NAV_LIST_PRUNED:
1370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RecordUpdatedNavListPruned(delta, use_long_period);
1371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RecordUpdatedSessionNavigationOrTab(delta, use_long_period);
1372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case NotificationType::NAV_ENTRY_COMMITTED:
1374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RecordUpdatedNavEntryCommit(delta, use_long_period);
1375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RecordUpdatedSessionNavigationOrTab(delta, use_long_period);
1376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
1378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED() << "Bad type sent to RecordSessionUpdateHistogramData";
1379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  (*last_updated_time) = base::TimeTicks::Now();
1383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::RecordUpdatedTabClosed(base::TimeDelta delta,
1386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            bool use_long_period) {
1387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string name("SessionRestore.TabClosedPeriod");
1388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_CUSTOM_TIMES(name,
1389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delta,
1390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // 2500ms is the default save delay.
1391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_millis_,
1392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_mins_,
1393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      50);
1394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (use_long_period) {
1395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string long_name_("SessionRestore.TabClosedLongPeriod");
1396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
1397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        delta,
1398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        save_delay_in_mins_,
1399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        save_delay_in_hrs_,
1400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        50);
1401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::RecordUpdatedNavListPruned(base::TimeDelta delta,
1405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                bool use_long_period) {
1406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string name("SessionRestore.NavigationListPrunedPeriod");
1407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_CUSTOM_TIMES(name,
1408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delta,
1409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // 2500ms is the default save delay.
1410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_millis_,
1411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_mins_,
1412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      50);
1413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (use_long_period) {
1414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string long_name_("SessionRestore.NavigationListPrunedLongPeriod");
1415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
1416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        delta,
1417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        save_delay_in_mins_,
1418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        save_delay_in_hrs_,
1419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        50);
1420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::RecordUpdatedNavEntryCommit(base::TimeDelta delta,
1424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                 bool use_long_period) {
1425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string name("SessionRestore.NavEntryCommittedPeriod");
1426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_CUSTOM_TIMES(name,
1427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delta,
1428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // 2500ms is the default save delay.
1429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_millis_,
1430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_mins_,
1431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      50);
1432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (use_long_period) {
1433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string long_name_("SessionRestore.NavEntryCommittedLongPeriod");
1434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
1435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        delta,
1436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        save_delay_in_mins_,
1437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        save_delay_in_hrs_,
1438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        50);
1439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::RecordUpdatedSessionNavigationOrTab(base::TimeDelta delta,
1443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                         bool use_long_period) {
1444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string name("SessionRestore.NavOrTabUpdatePeriod");
1445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_CUSTOM_TIMES(name,
1446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delta,
1447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // 2500ms is the default save delay.
1448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_millis_,
1449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_mins_,
1450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      50);
1451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (use_long_period) {
1452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string long_name_("SessionRestore.NavOrTabUpdateLongPeriod");
1453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
1454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        delta,
1455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        save_delay_in_mins_,
1456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        save_delay_in_hrs_,
1457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        50);
1458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SessionService::RecordUpdatedSaveTime(base::TimeDelta delta,
1462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           bool use_long_period) {
1463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string name("SessionRestore.SavePeriod");
1464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_CUSTOM_TIMES(name,
1465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delta,
1466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // 2500ms is the default save delay.
1467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_millis_,
1468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      save_delay_in_mins_,
1469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      50);
1470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (use_long_period) {
1471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string long_name_("SessionRestore.SaveLongPeriod");
1472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
1473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        delta,
1474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        save_delay_in_mins_,
1475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        save_delay_in_hrs_,
1476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        50);
1477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1479