Fix build break
[chromium-blink-merge.git] / chrome / browser / sessions / base_session_service.cc
blobb30abd8ec7d572e54d426165b5bfc76cf6f3791a
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sessions/base_session_service.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/pickle.h"
10 #include "base/stl_util.h"
11 #include "base/threading/thread.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/sessions/session_backend.h"
15 #include "chrome/browser/sessions/session_types.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/common/referrer.h"
20 #include "webkit/glue/webkit_glue.h"
22 using content::BrowserThread;
23 using content::NavigationEntry;
25 // BaseSessionService ---------------------------------------------------------
27 namespace {
29 // Helper used by CreateUpdateTabNavigationCommand(). It writes |str| to
30 // |pickle|, if and only if |str| fits within (|max_bytes| - |*bytes_written|).
31 // |bytes_written| is incremented to reflect the data written.
32 void WriteStringToPickle(Pickle& pickle, int* bytes_written, int max_bytes,
33 const std::string& str) {
34 int num_bytes = str.size() * sizeof(char);
35 if (*bytes_written + num_bytes < max_bytes) {
36 *bytes_written += num_bytes;
37 pickle.WriteString(str);
38 } else {
39 pickle.WriteString(std::string());
43 // Helper used by ScheduleGetLastSessionCommands. It runs callback on TaskRunner
44 // thread if it's not canceled.
45 void RunIfNotCanceled(
46 const CancelableTaskTracker::IsCanceledCallback& is_canceled,
47 const BaseSessionService::InternalGetCommandsCallback& callback,
48 ScopedVector<SessionCommand> commands) {
49 if (is_canceled.Run())
50 return;
51 callback.Run(commands.Pass());
54 void PostOrRunInternalGetCommandsCallback(
55 base::TaskRunner* task_runner,
56 const BaseSessionService::InternalGetCommandsCallback& callback,
57 ScopedVector<SessionCommand> commands) {
58 if (task_runner->RunsTasksOnCurrentThread()) {
59 callback.Run(commands.Pass());
60 } else {
61 task_runner->PostTask(FROM_HERE,
62 base::Bind(callback, base::Passed(&commands)));
66 } // namespace
68 // Delay between when a command is received, and when we save it to the
69 // backend.
70 static const int kSaveDelayMS = 2500;
72 // static
73 const int BaseSessionService::max_persist_navigation_count = 6;
75 BaseSessionService::BaseSessionService(SessionType type,
76 Profile* profile,
77 const base::FilePath& path)
78 : profile_(profile),
79 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
80 pending_reset_(false),
81 commands_since_reset_(0) {
82 if (profile) {
83 // We should never be created when incognito.
84 DCHECK(!profile->IsOffTheRecord());
86 backend_ = new SessionBackend(type, profile_ ? profile_->GetPath() : path);
87 DCHECK(backend_.get());
89 // SessionBackend::Init() cannot be scheduled to be called here. There are
90 // service processes which create the BaseSessionService, but they should not
91 // initialize the backend. If they do, the backend will cycle the session
92 // restore files. That in turn prevents the session restore from working when
93 // the normal chromium process is launched. Normally, the backend will be
94 // initialized before it's actually used. However, if we're running as a part
95 // of a test, it must be initialized now.
96 if (!RunningInProduction())
97 backend_->Init();
100 BaseSessionService::~BaseSessionService() {
103 void BaseSessionService::DeleteLastSession() {
104 RunTaskOnBackendThread(
105 FROM_HERE,
106 base::Bind(&SessionBackend::DeleteLastSession, backend()));
109 void BaseSessionService::ScheduleCommand(SessionCommand* command) {
110 DCHECK(command);
111 commands_since_reset_++;
112 pending_commands_.push_back(command);
113 StartSaveTimer();
116 void BaseSessionService::StartSaveTimer() {
117 // Don't start a timer when testing (profile == NULL or
118 // MessageLoop::current() is NULL).
119 if (MessageLoop::current() && profile() && !weak_factory_.HasWeakPtrs()) {
120 MessageLoop::current()->PostDelayedTask(
121 FROM_HERE,
122 base::Bind(&BaseSessionService::Save, weak_factory_.GetWeakPtr()),
123 base::TimeDelta::FromMilliseconds(kSaveDelayMS));
127 void BaseSessionService::Save() {
128 DCHECK(backend());
130 if (pending_commands_.empty())
131 return;
133 RunTaskOnBackendThread(
134 FROM_HERE,
135 base::Bind(&SessionBackend::AppendCommands, backend(),
136 new std::vector<SessionCommand*>(pending_commands_),
137 pending_reset_));
139 // Backend took ownership of commands.
140 pending_commands_.clear();
142 if (pending_reset_) {
143 commands_since_reset_ = 0;
144 pending_reset_ = false;
148 SessionCommand* BaseSessionService::CreateUpdateTabNavigationCommand(
149 SessionID::id_type command_id,
150 SessionID::id_type tab_id,
151 const TabNavigation& navigation) {
152 // Use pickle to handle marshalling.
153 Pickle pickle;
154 pickle.WriteInt(tab_id);
155 navigation.WriteToPickle(&pickle);
156 return new SessionCommand(command_id, pickle);
159 SessionCommand* BaseSessionService::CreateSetTabExtensionAppIDCommand(
160 SessionID::id_type command_id,
161 SessionID::id_type tab_id,
162 const std::string& extension_id) {
163 // Use pickle to handle marshalling.
164 Pickle pickle;
165 pickle.WriteInt(tab_id);
167 // Enforce a max for ids. They should never be anywhere near this size.
168 static const SessionCommand::size_type max_id_size =
169 std::numeric_limits<SessionCommand::size_type>::max() - 1024;
171 int bytes_written = 0;
173 WriteStringToPickle(pickle, &bytes_written, max_id_size, extension_id);
175 return new SessionCommand(command_id, pickle);
178 SessionCommand* BaseSessionService::CreateSetTabUserAgentOverrideCommand(
179 SessionID::id_type command_id,
180 SessionID::id_type tab_id,
181 const std::string& user_agent_override) {
182 // Use pickle to handle marshalling.
183 Pickle pickle;
184 pickle.WriteInt(tab_id);
186 // Enforce a max for the user agent length. They should never be anywhere
187 // near this size.
188 static const SessionCommand::size_type max_user_agent_size =
189 std::numeric_limits<SessionCommand::size_type>::max() - 1024;
191 int bytes_written = 0;
193 WriteStringToPickle(pickle, &bytes_written, max_user_agent_size,
194 user_agent_override);
196 return new SessionCommand(command_id, pickle);
199 SessionCommand* BaseSessionService::CreateSetWindowAppNameCommand(
200 SessionID::id_type command_id,
201 SessionID::id_type window_id,
202 const std::string& app_name) {
203 // Use pickle to handle marshalling.
204 Pickle pickle;
205 pickle.WriteInt(window_id);
207 // Enforce a max for ids. They should never be anywhere near this size.
208 static const SessionCommand::size_type max_id_size =
209 std::numeric_limits<SessionCommand::size_type>::max() - 1024;
211 int bytes_written = 0;
213 WriteStringToPickle(pickle, &bytes_written, max_id_size, app_name);
215 return new SessionCommand(command_id, pickle);
218 bool BaseSessionService::RestoreUpdateTabNavigationCommand(
219 const SessionCommand& command,
220 TabNavigation* navigation,
221 SessionID::id_type* tab_id) {
222 scoped_ptr<Pickle> pickle(command.PayloadAsPickle());
223 if (!pickle.get())
224 return false;
225 PickleIterator iterator(*pickle);
226 return
227 pickle->ReadInt(&iterator, tab_id) &&
228 navigation->ReadFromPickle(&iterator);
231 bool BaseSessionService::RestoreSetTabExtensionAppIDCommand(
232 const SessionCommand& command,
233 SessionID::id_type* tab_id,
234 std::string* extension_app_id) {
235 scoped_ptr<Pickle> pickle(command.PayloadAsPickle());
236 if (!pickle.get())
237 return false;
239 PickleIterator iterator(*pickle);
240 return pickle->ReadInt(&iterator, tab_id) &&
241 pickle->ReadString(&iterator, extension_app_id);
244 bool BaseSessionService::RestoreSetTabUserAgentOverrideCommand(
245 const SessionCommand& command,
246 SessionID::id_type* tab_id,
247 std::string* user_agent_override) {
248 scoped_ptr<Pickle> pickle(command.PayloadAsPickle());
249 if (!pickle.get())
250 return false;
252 PickleIterator iterator(*pickle);
253 return pickle->ReadInt(&iterator, tab_id) &&
254 pickle->ReadString(&iterator, user_agent_override);
257 bool BaseSessionService::RestoreSetWindowAppNameCommand(
258 const SessionCommand& command,
259 SessionID::id_type* window_id,
260 std::string* app_name) {
261 scoped_ptr<Pickle> pickle(command.PayloadAsPickle());
262 if (!pickle.get())
263 return false;
265 PickleIterator iterator(*pickle);
266 return pickle->ReadInt(&iterator, window_id) &&
267 pickle->ReadString(&iterator, app_name);
270 bool BaseSessionService::ShouldTrackEntry(const GURL& url) {
271 return url.is_valid();
274 CancelableTaskTracker::TaskId
275 BaseSessionService::ScheduleGetLastSessionCommands(
276 const InternalGetCommandsCallback& callback,
277 CancelableTaskTracker* tracker) {
278 CancelableTaskTracker::IsCanceledCallback is_canceled;
279 CancelableTaskTracker::TaskId id = tracker->NewTrackedTaskId(&is_canceled);
281 InternalGetCommandsCallback run_if_not_canceled =
282 base::Bind(&RunIfNotCanceled, is_canceled, callback);
284 InternalGetCommandsCallback callback_runner =
285 base::Bind(&PostOrRunInternalGetCommandsCallback,
286 base::MessageLoopProxy::current(), run_if_not_canceled);
288 RunTaskOnBackendThread(
289 FROM_HERE,
290 base::Bind(&SessionBackend::ReadLastSessionCommands, backend(),
291 is_canceled, callback_runner));
292 return id;
295 bool BaseSessionService::RunTaskOnBackendThread(
296 const tracked_objects::Location& from_here,
297 const base::Closure& task) {
298 if (profile_ && BrowserThread::IsMessageLoopValid(BrowserThread::FILE)) {
299 return BrowserThread::PostTask(BrowserThread::FILE, from_here, task);
300 } else {
301 // Fall back to executing on the main thread if the file thread
302 // has gone away (around shutdown time) or if we're running as
303 // part of a unit test that does not set profile_.
304 task.Run();
305 return true;
309 bool BaseSessionService::RunningInProduction() const {
310 return profile_ && BrowserThread::IsMessageLoopValid(BrowserThread::FILE);