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

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

Issue 8533013: SessionRestore: Store session cookies and restore them if chrome crashes or auto-restarts. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Cleanup. Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sessions/session_service.h" 5 #include "chrome/browser/sessions/session_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 #include <set> 9 #include <set>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/command_line.h"
12 #include "base/file_util.h" 13 #include "base/file_util.h"
14 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_vector.h" 15 #include "base/memory/scoped_vector.h"
14 #include "base/message_loop.h" 16 #include "base/message_loop.h"
15 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
16 #include "base/pickle.h" 18 #include "base/pickle.h"
17 #include "base/threading/thread.h" 19 #include "base/threading/thread.h"
18 #include "chrome/browser/extensions/extension_tab_helper.h" 20 #include "chrome/browser/extensions/extension_tab_helper.h"
21 #include "chrome/browser/net/chrome_cookie_notification_details.h"
22 #include "chrome/browser/net/sqlite_persistent_cookie_store.h"
23 #include "chrome/browser/prefs/pref_service.h"
19 #include "chrome/browser/prefs/session_startup_pref.h" 24 #include "chrome/browser/prefs/session_startup_pref.h"
20 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/sessions/restore_tab_helper.h" 26 #include "chrome/browser/sessions/restore_tab_helper.h"
22 #include "chrome/browser/sessions/session_backend.h" 27 #include "chrome/browser/sessions/session_backend.h"
23 #include "chrome/browser/sessions/session_command.h" 28 #include "chrome/browser/sessions/session_command.h"
24 #include "chrome/browser/sessions/session_restore.h" 29 #include "chrome/browser/sessions/session_restore.h"
25 #include "chrome/browser/sessions/session_types.h" 30 #include "chrome/browser/sessions/session_types.h"
26 #include "chrome/browser/tabs/tab_strip_model.h" 31 #include "chrome/browser/tabs/tab_strip_model.h"
27 #include "chrome/browser/ui/browser_init.h" 32 #include "chrome/browser/ui/browser_init.h"
28 #include "chrome/browser/ui/browser_list.h" 33 #include "chrome/browser/ui/browser_list.h"
29 #include "chrome/browser/ui/browser_window.h" 34 #include "chrome/browser/ui/browser_window.h"
30 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 35 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
31 #include "chrome/common/chrome_notification_types.h" 36 #include "chrome/common/chrome_notification_types.h"
37 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/extensions/extension.h" 38 #include "chrome/common/extensions/extension.h"
33 #include "content/browser/tab_contents/navigation_details.h" 39 #include "content/browser/tab_contents/navigation_details.h"
34 #include "content/browser/tab_contents/navigation_entry.h" 40 #include "content/browser/tab_contents/navigation_entry.h"
35 #include "content/browser/tab_contents/tab_contents.h" 41 #include "content/browser/tab_contents/tab_contents.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "content/public/browser/notification_details.h"
36 #include "content/public/browser/notification_service.h" 44 #include "content/public/browser/notification_service.h"
37 #include "content/public/browser/notification_details.h" 45 #include "net/base/cookie_monster.h"
46 #include "net/url_request/url_request_context.h"
47 #include "net/url_request/url_request_context_getter.h"
38 48
39 #if defined(OS_MACOSX) 49 #if defined(OS_MACOSX)
40 #include "chrome/browser/app_controller_cppsafe_mac.h" 50 #include "chrome/browser/app_controller_cppsafe_mac.h"
41 #endif 51 #endif
42 52
43 using base::Time; 53 using base::Time;
44 54
45 // Identifier for commands written to file. 55 // Identifier for commands written to file.
46 static const SessionCommand::id_type kCommandSetTabWindow = 0; 56 static const SessionCommand::id_type kCommandSetTabWindow = 0;
47 // OBSOLETE Superseded by kCommandSetWindowBounds3. 57 // OBSOLETE Superseded by kCommandSetWindowBounds3.
(...skipping 13 matching lines...) Expand all
61 kCommandTabNavigationPathPrunedFromFront = 11; 71 kCommandTabNavigationPathPrunedFromFront = 11;
62 static const SessionCommand::id_type kCommandSetPinnedState = 12; 72 static const SessionCommand::id_type kCommandSetPinnedState = 12;
63 static const SessionCommand::id_type kCommandSetExtensionAppID = 13; 73 static const SessionCommand::id_type kCommandSetExtensionAppID = 13;
64 static const SessionCommand::id_type kCommandSetWindowBounds3 = 14; 74 static const SessionCommand::id_type kCommandSetWindowBounds3 = 14;
65 75
66 // Every kWritesPerReset commands triggers recreating the file. 76 // Every kWritesPerReset commands triggers recreating the file.
67 static const int kWritesPerReset = 250; 77 static const int kWritesPerReset = 250;
68 78
69 namespace { 79 namespace {
70 80
81 const FilePath::CharType kSessionCookiesDatabaseName[] =
82 FILE_PATH_LITERAL("SessionCookies");
83
71 // The callback from GetLastSession is internally routed to SessionService 84 // The callback from GetLastSession is internally routed to SessionService
72 // first and then the caller. This is done so that the SessionWindows can be 85 // first and then the caller. This is done so that the SessionWindows can be
73 // recreated from the SessionCommands and the SessionWindows passed to the 86 // recreated from the SessionCommands and the SessionWindows passed to the
74 // caller. The following class is used for this. 87 // caller. The following class is used for this.
75 class InternalSessionRequest 88 class InternalSessionRequest
76 : public BaseSessionService::InternalGetCommandsRequest { 89 : public BaseSessionService::InternalGetCommandsRequest {
77 public: 90 public:
78 InternalSessionRequest( 91 InternalSessionRequest(
79 CallbackType* callback, 92 CallbackType* callback,
80 SessionService::SessionCallback* real_callback) 93 SessionService::SessionCallback* real_callback)
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 145
133 typedef IDAndIndexPayload TabNavigationPathPrunedFromFrontPayload; 146 typedef IDAndIndexPayload TabNavigationPathPrunedFromFrontPayload;
134 147
135 struct PinnedStatePayload { 148 struct PinnedStatePayload {
136 SessionID::id_type tab_id; 149 SessionID::id_type tab_id;
137 bool pinned_state; 150 bool pinned_state;
138 }; 151 };
139 152
140 } // namespace 153 } // namespace
141 154
155 // |SessionService::SessionCookieStore| stores session cookies in a
156 // |CookieMonster| and restores them. The constructor should be called in the
157 // UI thread, and all other functions should be called in the IO thread.
158 class SessionService::SessionCookieStore
159 : public base::RefCountedThreadSafe<
160 SessionCookieStore,
161 content::BrowserThread::DeleteOnIOThread> {
162 public:
163 typedef base::Callback<void()> CookieOperationCallback;
164
165 explicit SessionCookieStore(const FilePath& path)
166 : path_(path) {
167 content::BrowserThread::PostTask(
168 content::BrowserThread::IO, FROM_HERE,
169 base::Bind(&SessionCookieStore::InitializeOnIOThread, this));
170 }
171
172 ~SessionCookieStore() {
173 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
174 }
175
176 void RestoreSessionCookies(
177 net::URLRequestContextGetter* url_request_context_getter) {
178 net::CookieMonster* real_cookie_monster =
179 url_request_context_getter->GetURLRequestContext()->cookie_store()->
180 GetCookieMonster();
181 real_cookie_monster->MergeSessionCookies(session_cookie_monster_);
182 }
183
184 void ForgetSessionCookies() {
185 session_cookie_monster_->DeleteAllAsync(
186 net::CookieMonster::DeleteCallback());
187 }
188
189 class CanonicalCookieWrapper :
190 public base::RefCountedThreadSafe<CanonicalCookieWrapper> {
191 public:
192 explicit CanonicalCookieWrapper(
193 const net::CookieMonster::CanonicalCookie* cookie)
194 : cookie_(new net::CookieMonster::CanonicalCookie(*cookie)) {}
195 ~CanonicalCookieWrapper() {}
196
197 scoped_ptr<net::CookieMonster::CanonicalCookie> cookie_;
198 };
199
200 void AddSessionCookie(CanonicalCookieWrapper* wrapper) {
201 // Set the cookie as permanent so that |session_cookie_monster_| syncs it
202 // to its backend store.
203 wrapper->cookie_->SetPersistent(true);
204 net::CookieList cookie_list;
205 cookie_list.push_back(*(wrapper->cookie_));
206 session_cookie_monster_->InitializeFrom(cookie_list);
207 }
208
209 void RemoveSessionCookie(CanonicalCookieWrapper* wrapper,
210 const CookieOperationCallback& callback) {
211 session_cookie_monster_->DeleteCanonicalCookieAsync(
212 *(wrapper->cookie_),
213 base::Bind(&SessionCookieStore::OnCookieDeleted,
214 this,
215 callback));
216 }
217
218 private:
219 void InitializeOnIOThread() {
220 session_cookie_store_ = new SQLitePersistentCookieStore(path_);
221 session_cookie_monster_ =
222 new net::CookieMonster(session_cookie_store_.get(), NULL);
223 }
224
225 void OnCookieDeleted(const CookieOperationCallback& callback,
226 bool success) {
227 if (!callback.is_null()) {
228 content::BrowserThread::PostTask(
229 content::BrowserThread::UI, FROM_HERE,
230 base::Bind(&SessionCookieStore::InvokeCallback, this, callback));
231 }
232 }
233
234 void InvokeCallback(const CookieOperationCallback& callback) {
235 callback.Run();
236 }
237
238 FilePath path_;
239 scoped_refptr<SQLitePersistentCookieStore> session_cookie_store_;
240 scoped_refptr<net::CookieMonster> session_cookie_monster_;
241 };
242
142 // SessionService ------------------------------------------------------------- 243 // SessionService -------------------------------------------------------------
143 244
144 SessionService::SessionService(Profile* profile) 245 SessionService::SessionService(Profile* profile)
145 : BaseSessionService(SESSION_RESTORE, profile, FilePath()), 246 : BaseSessionService(SESSION_RESTORE, profile, FilePath()),
146 has_open_trackable_browsers_(false), 247 has_open_trackable_browsers_(false),
147 move_on_new_browser_(false), 248 move_on_new_browser_(false),
148 save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)), 249 save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
149 save_delay_in_mins_(base::TimeDelta::FromMinutes(10)), 250 save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
150 save_delay_in_hrs_(base::TimeDelta::FromHours(8)) { 251 save_delay_in_hrs_(base::TimeDelta::FromHours(8)),
252 enable_restore_session_data_(
253 CommandLine::ForCurrentProcess()->HasSwitch(
254 switches::kEnableRestoreSessionState)) {
151 Init(); 255 Init();
152 } 256 }
153 257
154 SessionService::SessionService(const FilePath& save_path) 258 SessionService::SessionService(const FilePath& save_path)
155 : BaseSessionService(SESSION_RESTORE, NULL, save_path), 259 : BaseSessionService(SESSION_RESTORE, NULL, save_path),
156 has_open_trackable_browsers_(false), 260 has_open_trackable_browsers_(false),
157 move_on_new_browser_(false), 261 move_on_new_browser_(false),
158 save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)), 262 save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
159 save_delay_in_mins_(base::TimeDelta::FromMinutes(10)), 263 save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
160 save_delay_in_hrs_(base::TimeDelta::FromHours(8)) { 264 save_delay_in_hrs_(base::TimeDelta::FromHours(8)),
265 enable_restore_session_data_(
266 CommandLine::ForCurrentProcess()->HasSwitch(
267 switches::kEnableRestoreSessionState)) {
161 Init(); 268 Init();
162 } 269 }
163 270
164 SessionService::~SessionService() { 271 SessionService::~SessionService() {
165 Save(); 272 Save();
166 } 273 }
167 274
168 bool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open) { 275 bool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open) {
169 return RestoreIfNecessary(urls_to_open, NULL); 276 return RestoreIfNecessary(urls_to_open, NULL);
170 } 277 }
171 278
172 void SessionService::ResetFromCurrentBrowsers() { 279 void SessionService::ResetFromCurrentBrowsers() {
173 ScheduleReset(); 280 ScheduleReset();
174 } 281 }
175 282
176 void SessionService::MoveCurrentSessionToLastSession() { 283 void SessionService::MoveCurrentSessionToLastSession() {
177 pending_tab_close_ids_.clear(); 284 pending_tab_close_ids_.clear();
178 window_closing_ids_.clear(); 285 window_closing_ids_.clear();
179 pending_window_close_ids_.clear(); 286 pending_window_close_ids_.clear();
180 287
181 Save(); 288 Save();
182 289
290 content::BrowserThread::PostTask(
291 content::BrowserThread::IO, FROM_HERE,
292 base::Bind(
293 &SessionCookieStore::ForgetSessionCookies,
294 session_cookie_store_));
295
183 if (!backend_thread()) { 296 if (!backend_thread()) {
184 backend()->MoveCurrentSessionToLastSession(); 297 backend()->MoveCurrentSessionToLastSession();
185 } else { 298 } else {
186 backend_thread()->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 299 backend_thread()->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
187 backend(), &SessionBackend::MoveCurrentSessionToLastSession)); 300 backend(), &SessionBackend::MoveCurrentSessionToLastSession));
188 } 301 }
189 } 302 }
190 303
191 void SessionService::SetTabWindow(const SessionID& window_id, 304 void SessionService::SetTabWindow(const SessionID& window_id,
192 const SessionID& tab_id) { 305 const SessionID& tab_id) {
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 RecordSessionUpdateHistogramData( 571 RecordSessionUpdateHistogramData(
459 chrome::NOTIFICATION_SESSION_SERVICE_SAVED, 572 chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
460 &last_updated_save_time_); 573 &last_updated_save_time_);
461 content::NotificationService::current()->Notify( 574 content::NotificationService::current()->Notify(
462 chrome::NOTIFICATION_SESSION_SERVICE_SAVED, 575 chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
463 content::Source<Profile>(profile()), 576 content::Source<Profile>(profile()),
464 content::NotificationService::NoDetails()); 577 content::NotificationService::NoDetails());
465 } 578 }
466 } 579 }
467 580
581 void SessionService::RestoreOrResetSessionState(bool restore) {
582 // Schedule the restoring or deletion of the session cookies in the IO
583 // thread. |RestoreSessionCookies| (or |ForgetSessionCookies|) will be
584 // executed be done before any cookies are served, since the cookies will be
585 // served on the IO thread.
586 if (!session_cookie_store_.get())
587 return;
588
589 bool restore_session_cookies = enable_restore_session_data_ &&
590 restore &&
591 profile();
592 if (restore_session_cookies) {
593 content::BrowserThread::PostTask(
594 content::BrowserThread::IO, FROM_HERE,
595 base::Bind(
596 &SessionCookieStore::RestoreSessionCookies,
597 session_cookie_store_,
598 make_scoped_refptr(profile()->GetRequestContext())));
599 } else {
600 content::BrowserThread::PostTask(
601 content::BrowserThread::IO, FROM_HERE,
602 base::Bind(
603 &SessionCookieStore::ForgetSessionCookies,
604 session_cookie_store_));
605 }
606 }
607
468 void SessionService::Init() { 608 void SessionService::Init() {
469 // Register for the notifications we're interested in. 609 // Register for the notifications we're interested in.
470 registrar_.Add(this, content::NOTIFICATION_TAB_PARENTED, 610 registrar_.Add(this, content::NOTIFICATION_TAB_PARENTED,
471 content::NotificationService::AllSources()); 611 content::NotificationService::AllSources());
472 registrar_.Add(this, content::NOTIFICATION_TAB_CLOSED, 612 registrar_.Add(this, content::NOTIFICATION_TAB_CLOSED,
473 content::NotificationService::AllSources()); 613 content::NotificationService::AllSources());
474 registrar_.Add(this, content::NOTIFICATION_NAV_LIST_PRUNED, 614 registrar_.Add(this, content::NOTIFICATION_NAV_LIST_PRUNED,
475 content::NotificationService::AllSources()); 615 content::NotificationService::AllSources());
476 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED, 616 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED,
477 content::NotificationService::AllSources()); 617 content::NotificationService::AllSources());
478 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 618 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
479 content::NotificationService::AllSources()); 619 content::NotificationService::AllSources());
480 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, 620 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
481 content::NotificationService::AllBrowserContextsAndSources()); 621 content::NotificationService::AllBrowserContextsAndSources());
482 registrar_.Add( 622 registrar_.Add(
483 this, chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, 623 this, chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
484 content::NotificationService::AllSources()); 624 content::NotificationService::AllSources());
625 if (enable_restore_session_data_ && profile()) {
626 registrar_.Add(
627 this, chrome::NOTIFICATION_COOKIE_CHANGED,
628 content::Source<Profile>(profile()));
629 session_cookie_store_ = new SessionCookieStore(
630 profile()->GetPath().Append(kSessionCookiesDatabaseName));
631 }
485 } 632 }
486 633
487 bool SessionService::ShouldNewWindowStartSession() { 634 bool SessionService::ShouldNewWindowStartSession() {
488 if (!has_open_trackable_browsers_ && !BrowserInit::InProcessStartup() && 635 if (!has_open_trackable_browsers_ && !BrowserInit::InProcessStartup() &&
489 !SessionRestore::IsRestoring() 636 !SessionRestore::IsRestoring()
490 #if defined(OS_MACOSX) 637 #if defined(OS_MACOSX)
491 // OSX has a fairly different idea of application lifetime than the 638 // OSX has a fairly different idea of application lifetime than the
492 // other platforms. We need to check that we aren't opening a window 639 // other platforms. We need to check that we aren't opening a window
493 // from the dock or the menubar. 640 // from the dock or the menubar.
494 && !app_controller_mac::IsOpeningNewWindow() 641 && !app_controller_mac::IsOpeningNewWindow()
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
643 if (extension_tab_helper->extension_app()) { 790 if (extension_tab_helper->extension_app()) {
644 RestoreTabHelper* helper = 791 RestoreTabHelper* helper =
645 extension_tab_helper->tab_contents_wrapper()->restore_tab_helper(); 792 extension_tab_helper->tab_contents_wrapper()->restore_tab_helper();
646 SetTabExtensionAppID(helper->window_id(), 793 SetTabExtensionAppID(helper->window_id(),
647 helper->session_id(), 794 helper->session_id(),
648 extension_tab_helper->extension_app()->id()); 795 extension_tab_helper->extension_app()->id());
649 } 796 }
650 break; 797 break;
651 } 798 }
652 799
800 case chrome::NOTIFICATION_COOKIE_CHANGED: {
801 if (enable_restore_session_data_ && session_cookie_store_.get()) {
802 ChromeCookieDetails* cookie_details =
803 content::Details<ChromeCookieDetails>(details).ptr();
804 if (!cookie_details->cookie->IsPersistent()) {
805 scoped_refptr<SessionCookieStore::CanonicalCookieWrapper> cookie =
806 new SessionCookieStore::CanonicalCookieWrapper(
807 cookie_details->cookie);
808 if (cookie_details->removed) {
809 content::BrowserThread::PostTask(
810 content::BrowserThread::IO, FROM_HERE,
811 base::Bind(
812 &SessionCookieStore::RemoveSessionCookie,
813 session_cookie_store_,
814 cookie,
815 SessionCookieStore::CookieOperationCallback()));
816 } else {
817 content::BrowserThread::PostTask(
818 content::BrowserThread::IO, FROM_HERE,
819 base::Bind(
820 &SessionCookieStore::AddSessionCookie,
821 session_cookie_store_,
822 cookie));
823 }
824 }
825 }
826 break;
827 }
828
653 default: 829 default:
654 NOTREACHED(); 830 NOTREACHED();
655 } 831 }
656 } 832 }
657 833
658 void SessionService::SetTabExtensionAppID( 834 void SessionService::SetTabExtensionAppID(
659 const SessionID& window_id, 835 const SessionID& window_id,
660 const SessionID& tab_id, 836 const SessionID& tab_id,
661 const std::string& extension_app_id) { 837 const std::string& extension_app_id) {
662 if (!ShouldTrackChangesToWindow(window_id)) 838 if (!ShouldTrackChangesToWindow(window_id))
(...skipping 870 matching lines...) Expand 10 before | Expand all | Expand 10 after
1533 50); 1709 50);
1534 if (use_long_period) { 1710 if (use_long_period) {
1535 std::string long_name_("SessionRestore.SaveLongPeriod"); 1711 std::string long_name_("SessionRestore.SaveLongPeriod");
1536 UMA_HISTOGRAM_CUSTOM_TIMES(long_name_, 1712 UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
1537 delta, 1713 delta,
1538 save_delay_in_mins_, 1714 save_delay_in_mins_,
1539 save_delay_in_hrs_, 1715 save_delay_in_hrs_,
1540 50); 1716 50);
1541 } 1717 }
1542 } 1718 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698