| Index: chrome/browser/sessions/session_service.cc
|
| diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc
|
| index 7ec80a4ce19f92227e97578a6438b2a3fa96190a..7d6acc2d3a690eea2b248fdf071188b7a10ce00f 100644
|
| --- a/chrome/browser/sessions/session_service.cc
|
| +++ b/chrome/browser/sessions/session_service.cc
|
| @@ -2,6 +2,8 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include "content/public/browser/browser_thread.h"
|
| +
|
| #include "chrome/browser/sessions/session_service.h"
|
|
|
| #include <algorithm>
|
| @@ -32,6 +34,10 @@
|
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
|
| #include "chrome/common/chrome_notification_types.h"
|
| #include "chrome/common/extensions/extension.h"
|
| +#include "content/browser/in_process_webkit/dom_storage_context.h"
|
| +#include "content/browser/in_process_webkit/dom_storage_namespace.h"
|
| +#include "content/browser/in_process_webkit/session_storage_namespace.h"
|
| +#include "content/browser/in_process_webkit/webkit_context.h"
|
| #include "content/public/browser/navigation_details.h"
|
| #include "content/public/browser/navigation_entry.h"
|
| #include "content/public/browser/notification_service.h"
|
| @@ -65,6 +71,7 @@ static const SessionCommand::id_type
|
| static const SessionCommand::id_type kCommandSetPinnedState = 12;
|
| static const SessionCommand::id_type kCommandSetExtensionAppID = 13;
|
| static const SessionCommand::id_type kCommandSetWindowBounds3 = 14;
|
| +static const SessionCommand::id_type kCommandSessionStorageCreated = 15;
|
|
|
| // Every kWritesPerReset commands triggers recreating the file.
|
| static const int kWritesPerReset = 250;
|
| @@ -142,6 +149,56 @@ struct PinnedStatePayload {
|
|
|
| } // namespace
|
|
|
| +// SessionService needs to read data from DOMStorageContext and it can be only
|
| +// done on the WEBKIT_DEPRECATED thread. This class is for reading the data. It
|
| +// also takes into account that SessionService might get deleted before we have
|
| +// a change to call it back.
|
| +class SessionService::SessionStorageAssociationReader
|
| + : public base::RefCountedThreadSafe<
|
| + SessionService::SessionStorageAssociationReader> {
|
| + public:
|
| + SessionStorageAssociationReader(SessionService* session_service,
|
| + int64 namespace_id,
|
| + WebKitContext* webkit_context)
|
| + : session_service_(session_service),
|
| + namespace_id_(namespace_id),
|
| + webkit_context_(webkit_context) {
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::WEBKIT_DEPRECATED, FROM_HERE,
|
| + base::Bind(&SessionStorageAssociationReader::ReadData, this));
|
| + }
|
| + ~SessionStorageAssociationReader() { }
|
| +
|
| + private:
|
| + friend class SessionService;
|
| +
|
| + void ReadData() {
|
| + DOMStorageNamespace* dom_storage_namespace = webkit_context_->
|
| + dom_storage_context()->GetStorageNamespace(namespace_id_, false);
|
| + if (dom_storage_namespace != NULL) {
|
| + session_storage_directory_ =
|
| + dom_storage_namespace->session_storage_directory();
|
| + }
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&SessionStorageAssociationReader::ForwardData, this));
|
| + }
|
| +
|
| + void ForwardData() {
|
| + // If SessionService gets destroyed before this object, it nullifies this
|
| + // pointer.
|
| + if (session_service_) {
|
| + session_service_->AssociateSessionStorage(this, namespace_id_,
|
| + session_storage_directory_);
|
| + }
|
| + }
|
| +
|
| + SessionService* session_service_;
|
| + int64 namespace_id_;
|
| + WebKitContext* webkit_context_;
|
| + FilePath session_storage_directory_;
|
| +};
|
| +
|
| // SessionService -------------------------------------------------------------
|
|
|
| SessionService::SessionService(Profile* profile)
|
| @@ -166,6 +223,17 @@ SessionService::SessionService(const FilePath& save_path)
|
|
|
| SessionService::~SessionService() {
|
| Save();
|
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| + for (SessionStorageAssociationReaders::const_iterator it =
|
| + session_storage_association_readers_.begin();
|
| + it != session_storage_association_readers_.end();
|
| + ++it) {
|
| + // This is done in the UI thread. SessionStorageAssociationReader only
|
| + // accesses session_service_ in the UI thread, so this is safe.
|
| + it->first->session_service_ = NULL;
|
| + }
|
| + // References from SessionService to SessionStorageAssociationReader will be
|
| + // automatically dropped as session_storage_association_readers_ is destroyed.
|
| }
|
|
|
| bool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open) {
|
| @@ -457,6 +525,8 @@ void SessionService::Init() {
|
| registrar_.Add(
|
| this, chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
|
| content::NotificationService::AllSources());
|
| + registrar_.Add(this, content::NOTIFICATION_SESSION_STORAGE_NAMESPACE_CREATED,
|
| + content::NotificationService::AllSources());
|
| }
|
|
|
| bool SessionService::ShouldNewWindowStartSession() {
|
| @@ -519,6 +589,15 @@ void SessionService::Observe(int type,
|
| content::Source<TabContentsWrapper>(source).ptr();
|
| if (tab->profile() != profile())
|
| return;
|
| +
|
| + // Record the association between the sessionStorage namespace and the
|
| + // tab.
|
| + SessionStorageNamespace* session_storage_namespace =
|
| + tab->web_contents()->GetController().GetSessionStorageNamespace();
|
| + session_storage_namespace_map_[session_storage_namespace->id()] =
|
| + std::make_pair(tab->restore_tab_helper()->window_id(),
|
| + tab->restore_tab_helper()->session_id());
|
| +
|
| SetTabWindow(tab->restore_tab_helper()->window_id(),
|
| tab->restore_tab_helper()->session_id());
|
| if (tab->extension_tab_helper()->extension_app()) {
|
| @@ -627,6 +706,15 @@ void SessionService::Observe(int type,
|
| break;
|
| }
|
|
|
| + case content::NOTIFICATION_SESSION_STORAGE_NAMESPACE_CREATED: {
|
| + content::Details<SessionStorageCreatedDetails>
|
| + namespace_created_details(details);
|
| + CreateAndScheduleSessionStorageCreatedCommand(
|
| + namespace_created_details->id,
|
| + namespace_created_details->session_storage_directory);
|
| + break;
|
| + }
|
| +
|
| default:
|
| NOTREACHED();
|
| }
|
| @@ -760,6 +848,21 @@ SessionCommand* SessionService::CreatePinnedStateCommand(
|
| return command;
|
| }
|
|
|
| +void SessionService::CreateAndScheduleSessionStorageCreatedCommand(
|
| + int64 namespace_id,
|
| + const FilePath& directory) {
|
| + SessionStorageNamespaceMap::const_iterator it =
|
| + session_storage_namespace_map_.find(namespace_id);
|
| + if (it != session_storage_namespace_map_.end()) {
|
| + Pickle session_storage_created_pickle;
|
| + session_storage_created_pickle.WriteInt(it->second.first.id());
|
| + session_storage_created_pickle.WriteInt(it->second.second.id());
|
| + session_storage_created_pickle.WriteString(directory.value());
|
| + ScheduleCommand(new SessionCommand(kCommandSessionStorageCreated,
|
| + session_storage_created_pickle));
|
| + }
|
| +}
|
| +
|
| void SessionService::OnGotSessionCommands(
|
| Handle handle,
|
| scoped_refptr<InternalGetCommandsRequest> request) {
|
| @@ -779,11 +882,20 @@ void SessionService::RestoreSessionFromCommands(
|
| std::map<int, SessionTab*> tabs;
|
| std::map<int, SessionWindow*> windows;
|
|
|
| - if (CreateTabsAndWindows(commands, &tabs, &windows)) {
|
| + // Keeps track of which sessionStorages are in use after session restore, so
|
| + // that the rest can be deleted.
|
| + std::set<std::string> needed_session_storages;
|
| +
|
| + if (CreateTabsAndWindows(commands, &tabs, &windows,
|
| + &needed_session_storages)) {
|
| AddTabsToWindows(&tabs, &windows);
|
| SortTabsBasedOnVisualOrderAndPrune(&windows, valid_windows);
|
| UpdateSelectedTabIndex(valid_windows);
|
| }
|
| +
|
| + profile()->GetWebKitContext()->DeleteUnneededSessionStorages(
|
| + needed_session_storages);
|
| +
|
| STLDeleteValues(&tabs);
|
| // Don't delete conents of windows, that is done by the caller as all
|
| // valid windows are added to valid_windows.
|
| @@ -921,7 +1033,8 @@ void SessionService::AddTabsToWindows(std::map<int, SessionTab*>* tabs,
|
| bool SessionService::CreateTabsAndWindows(
|
| const std::vector<SessionCommand*>& data,
|
| std::map<int, SessionTab*>* tabs,
|
| - std::map<int, SessionWindow*>* windows) {
|
| + std::map<int, SessionWindow*>* windows,
|
| + std::set<std::string>* needed_session_storages) {
|
| // If the file is corrupt (command with wrong size, or unknown command), we
|
| // still return true and attempt to restore what we we can.
|
|
|
| @@ -1097,6 +1210,20 @@ bool SessionService::CreateTabsAndWindows(
|
| GetTab(tab_id, tabs)->extension_app_id.swap(extension_app_id);
|
| break;
|
| }
|
| + case kCommandSessionStorageCreated: {
|
| + scoped_ptr<Pickle> pickle(command->PayloadAsPickle());
|
| + SessionID::id_type window_id;
|
| + SessionID::id_type tab_id;
|
| + std::string session_storage_directory;
|
| + void* iter = NULL;
|
| + pickle->ReadInt(&iter, &window_id);
|
| + pickle->ReadInt(&iter, &tab_id);
|
| + pickle->ReadString(&iter, &session_storage_directory);
|
| + GetTab(tab_id, tabs)->session_storage_directory =
|
| + FilePath(session_storage_directory);
|
| + needed_session_storages->insert(session_storage_directory);
|
| + break;
|
| + }
|
|
|
| default:
|
| return true;
|
| @@ -1115,6 +1242,16 @@ void SessionService::BuildCommandsForTab(
|
| DCHECK(tab && commands && window_id.id());
|
| const SessionID& session_id(tab->restore_tab_helper()->session_id());
|
| commands->push_back(CreateSetTabWindowCommand(window_id, session_id));
|
| +
|
| + // Schedule reading the session storage directory on the WEBKIT_DEPRECATED
|
| + // thread.
|
| + int64 namespace_id =
|
| + tab->web_contents()->GetController().GetSessionStorageNamespace()->id();
|
| + WebKitContext* webkit_context = profile()->GetWebKitContext();
|
| + scoped_refptr<SessionStorageAssociationReader> reader =
|
| + new SessionStorageAssociationReader(this, namespace_id, webkit_context);
|
| + session_storage_association_readers_[reader.get()] = reader;
|
| +
|
| const int current_index =
|
| tab->web_contents()->GetController().GetCurrentEntryIndex();
|
| const int min_index = std::max(0,
|
| @@ -1519,3 +1656,14 @@ void SessionService::RecordUpdatedSaveTime(base::TimeDelta delta,
|
| 50);
|
| }
|
| }
|
| +
|
| +void SessionService::AssociateSessionStorage(
|
| + SessionStorageAssociationReader* reader,
|
| + int64 namespace_id,
|
| + const FilePath& directory) {
|
| + if (!directory.empty()) {
|
| + CreateAndScheduleSessionStorageCreatedCommand(
|
| + namespace_id, directory);
|
| + }
|
| + session_storage_association_readers_.erase(reader);
|
| +}
|
|
|