summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc356
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h70
-rw-r--r--chrome/browser/in_process_webkit/webkit_thread.cc38
-rw-r--r--chrome/browser/in_process_webkit/webkit_thread.h14
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc3
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc6
6 files changed, 465 insertions, 22 deletions
diff --git a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
index 1ea105c..8ef7ca4 100644
--- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
+++ b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
@@ -4,9 +4,19 @@
#include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h"
+#include "base/stl_util-inl.h"
+#include "base/string16.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "chrome/browser/in_process_webkit/webkit_thread.h"
+#include "chrome/common/render_messages.h"
+#include "webkit/api/public/WebKit.h"
+#include "webkit/api/public/WebStorageArea.h"
+#include "webkit/api/public/WebStorageNamespace.h"
+#include "webkit/api/public/WebString.h"
+
+using WebKit::WebStorageArea;
+using WebKit::WebStorageNamespace;
DOMStorageDispatcherHost::DOMStorageDispatcherHost(
IPC::Message::Sender* message_sender,
@@ -14,24 +24,78 @@ DOMStorageDispatcherHost::DOMStorageDispatcherHost(
WebKitThread* webkit_thread)
: webkit_context_(webkit_context),
webkit_thread_(webkit_thread),
- message_sender_(message_sender) {
+ message_sender_(message_sender),
+ last_storage_area_id_(0),
+ last_storage_namespace_id_(0),
+ ever_used_(false),
+ shutdown_(false) {
DCHECK(webkit_context_.get());
DCHECK(webkit_thread_);
DCHECK(message_sender_);
}
DOMStorageDispatcherHost::~DOMStorageDispatcherHost() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- message_sender_ = NULL;
+ DCHECK(!ever_used_ || ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ DCHECK(shutdown_);
+}
+
+void DOMStorageDispatcherHost::Shutdown() {
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ message_sender_ = NULL;
+ if (!ever_used_) {
+ shutdown_ = true;
+ return;
+ }
+
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::Shutdown));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ DCHECK(ever_used_);
+ DCHECK(!message_sender_);
+ DCHECK(!shutdown_);
+
+ STLDeleteContainerPairSecondPointers(storage_area_map_.begin(),
+ storage_area_map_.end());
+ STLDeleteContainerPairSecondPointers(storage_namespace_map_.begin(),
+ storage_namespace_map_.end());
+ shutdown_ = true;
}
-bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& msg) {
- // TODO(jorlow): Implement DOM Storage's message handler...and the rest
- // of DOM Storage. :-)
- return false;
+bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& message,
+ bool *msg_is_ok) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ DCHECK(!shutdown_);
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageDispatcherHost, message, *msg_is_ok)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageNamespaceId,
+ OnNamespaceId)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageCloneNamespaceId,
+ OnCloneNamespaceId)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageDerefNamespaceId,
+ OnDerefNamespaceId)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageStorageAreaId,
+ OnStorageAreaId)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageLock, OnLock)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageUnlock, OnUnlock)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageLength, OnLength)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageKey, OnKey)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageGetItem, OnGetItem)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageSetItem, OnSetItem)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageRemoveItem, OnRemoveItem)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageClear, OnClear)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ if (handled)
+ ever_used_ = true;
+ return handled;
}
void DOMStorageDispatcherHost::Send(IPC::Message* message) {
+ DCHECK(!shutdown_);
if (!message_sender_) {
delete message;
return;
@@ -42,11 +106,277 @@ void DOMStorageDispatcherHost::Send(IPC::Message* message) {
return;
}
- // The IO thread can't dissapear while the WebKit thread is still running.
+ // The IO thread can't go away while the WebKit thread is still running.
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ webkit_thread_->PostIOThreadTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::Send, message));
+}
+
+void DOMStorageDispatcherHost::OnNamespaceId(bool is_local_storage,
+ IPC::Message* reply_msg) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnNamespaceId,
+ is_local_storage, reply_msg));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebStorageNamespace* new_namespace;
+ if (is_local_storage) {
+ new_namespace = WebStorageNamespace::createLocalStorageNamespace(
+ GetLocalStoragePath());
+ } else {
+ new_namespace = WebStorageNamespace::createSessionStorageNamespace();
+ }
+ int64 new_namespace_id = AddStorageNamespace(new_namespace);
+ ViewHostMsg_DOMStorageNamespaceId::WriteReplyParams(reply_msg,
+ new_namespace_id);
+ Send(reply_msg);
+}
+
+void DOMStorageDispatcherHost::OnCloneNamespaceId(int64 namespace_id,
+ IPC::Message* reply_msg) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnCloneNamespaceId,
+ namespace_id, reply_msg));
+ return;
+ }
+
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
- MessageLoop* io_loop = ChromeThread::GetMessageLoop(ChromeThread::IO);
- CancelableTask* task = NewRunnableMethod(this,
- &DOMStorageDispatcherHost::Send,
- message);
- io_loop->PostTask(FROM_HERE, task);
+ WebStorageNamespace* existing_namespace = GetStorageNamespace(namespace_id);
+ CHECK(existing_namespace); // TODO(jorlow): Do better than this.
+ WebStorageNamespace* new_namespace = existing_namespace->copy();
+ int64 new_namespace_id = AddStorageNamespace(new_namespace);
+ ViewHostMsg_DOMStorageCloneNamespaceId::WriteReplyParams(reply_msg,
+ new_namespace_id);
+ Send(reply_msg);
+}
+
+void DOMStorageDispatcherHost::OnDerefNamespaceId(int64 namespace_id) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnDerefNamespaceId, namespace_id));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ // TODO(jorlow): We need to track resources so we can free them.
+}
+
+void DOMStorageDispatcherHost::OnStorageAreaId(int64 namespace_id,
+ const string16& origin,
+ IPC::Message* reply_msg) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnStorageAreaId,
+ namespace_id, origin, reply_msg));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebStorageNamespace* storage_namespace = GetStorageNamespace(namespace_id);
+ CHECK(storage_namespace); // TODO(jorlow): Do better than this.
+ WebStorageArea* storage_area = storage_namespace->createStorageArea(origin);
+ int64 storage_area_id = AddStorageArea(storage_area);
+ ViewHostMsg_DOMStorageCloneNamespaceId::WriteReplyParams(reply_msg,
+ storage_area_id);
+ Send(reply_msg);
+}
+
+void DOMStorageDispatcherHost::OnLock(int64 storage_area_id,
+ IPC::Message* reply_msg) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnLock, storage_area_id, reply_msg));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ bool invalidate_cache;
+ size_t bytes_left_in_quota;
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id);
+ CHECK(storage_area); // TODO(jorlow): Do better than this.
+ storage_area->lock(invalidate_cache, bytes_left_in_quota);
+ ViewHostMsg_DOMStorageLock::WriteReplyParams(reply_msg, invalidate_cache,
+ bytes_left_in_quota);
+ Send(reply_msg);
+}
+
+void DOMStorageDispatcherHost::OnUnlock(int64 storage_area_id) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnUnlock, storage_area_id));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id);
+ CHECK(storage_area); // TODO(jorlow): Do better than this.
+ storage_area->unlock();
+}
+
+void DOMStorageDispatcherHost::OnLength(int64 storage_area_id,
+ IPC::Message* reply_msg) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnLength, storage_area_id, reply_msg));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id);
+ CHECK(storage_area); // TODO(jorlow): Do better than this.
+ unsigned length = storage_area->length();
+ ViewHostMsg_DOMStorageLength::WriteReplyParams(reply_msg, length);
+ Send(reply_msg);
+}
+
+void DOMStorageDispatcherHost::OnKey(int64 storage_area_id, unsigned index,
+ IPC::Message* reply_msg) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnKey, storage_area_id, index, reply_msg));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ bool key_exception = false;
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id);
+ CHECK(storage_area); // TODO(jorlow): Do better than this.
+ string16 key = storage_area->key(index, key_exception);
+ ViewHostMsg_DOMStorageKey::WriteReplyParams(reply_msg, key_exception, key);
+ Send(reply_msg);
+}
+
+void DOMStorageDispatcherHost::OnGetItem(int64 storage_area_id,
+ const string16& key,
+ IPC::Message* reply_msg) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnGetItem,
+ storage_area_id, key, reply_msg));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id);
+ CHECK(storage_area); // TODO(jorlow): Do better than this.
+ WebKit::WebString value = storage_area->getItem(key);
+ ViewHostMsg_DOMStorageGetItem::WriteReplyParams(reply_msg, (string16)value,
+ value.isNull());
+ Send(reply_msg);
+}
+
+void DOMStorageDispatcherHost::OnSetItem(int64 storage_area_id,
+ const string16& key,
+ const string16& value) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnSetItem, storage_area_id, key, value));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ bool quota_exception = false;
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id);
+ CHECK(storage_area); // TODO(jorlow): Do better than this.
+ storage_area->setItem(key, value, quota_exception);
+ DCHECK(!quota_exception); // This is tracked by the renderer.
+}
+
+void DOMStorageDispatcherHost::OnRemoveItem(int64 storage_area_id,
+ const string16& key) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnRemoveItem, storage_area_id, key));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id);
+ CHECK(storage_area); // TODO(jorlow): Do better than this.
+ storage_area->removeItem(key);
+}
+
+void DOMStorageDispatcherHost::OnClear(int64 storage_area_id,
+ IPC::Message* reply_msg) {
+ DCHECK(!shutdown_);
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop();
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &DOMStorageDispatcherHost::OnClear, storage_area_id, reply_msg));
+ return;
+ }
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ // TODO(jorlow): Return the total quota for this domain.
+ size_t bytes_left_in_quota = 0;
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id);
+ CHECK(storage_area); // TODO(jorlow): Do better than this.
+ storage_area->clear();
+ ViewHostMsg_DOMStorageClear::WriteReplyParams(reply_msg,
+ bytes_left_in_quota);
+ Send(reply_msg);
+}
+
+WebStorageArea* DOMStorageDispatcherHost::GetStorageArea(int64 id) {
+ StorageAreaMap::iterator iterator = storage_area_map_.find(id);
+ if (iterator == storage_area_map_.end())
+ return NULL;
+ return iterator->second;
+}
+
+WebStorageNamespace* DOMStorageDispatcherHost::GetStorageNamespace(int64 id) {
+ StorageNamespaceMap::iterator iterator = storage_namespace_map_.find(id);
+ if (iterator == storage_namespace_map_.end())
+ return NULL;
+ return iterator->second;
+}
+
+int64 DOMStorageDispatcherHost::AddStorageArea(
+ WebStorageArea* new_storage_area) {
+ // Create a new ID and insert it into our map.
+ int64 new_storage_area_id = ++last_storage_area_id_;
+ DCHECK(!GetStorageArea(new_storage_area_id));
+ storage_area_map_[new_storage_area_id] = new_storage_area;
+ return new_storage_area_id;
+}
+
+int64 DOMStorageDispatcherHost::AddStorageNamespace(
+ WebStorageNamespace* new_namespace) {
+ // Create a new ID and insert it into our map.
+ int64 new_namespace_id = ++last_storage_namespace_id_;
+ DCHECK(!GetStorageNamespace(new_namespace_id));
+ storage_namespace_map_[new_namespace_id] = new_namespace;
+ return new_namespace_id;
+}
+
+string16 DOMStorageDispatcherHost::GetLocalStoragePath() {
+ // TODO(jorlow): Create a path based on the WebKitContext.
+ string16 path;
+ return path;
}
diff --git a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h
index edc8822..8e7e12f 100644
--- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h
+++ b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h
@@ -5,16 +5,22 @@
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_DISPATCHER_HOST_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_DISPATCHER_HOST_H_
+#include "base/hash_tables.h"
+#include "base/scoped_ptr.h"
#include "base/ref_counted.h"
#include "ipc/ipc_message.h"
class WebKitContext;
class WebKitThread;
+namespace WebKit {
+class WebStorageArea;
+class WebStorageNamespace;
+}
+
// This class handles the logistics of DOM Storage within the browser process.
// It mostly ferries information between IPCs and the WebKit implementations,
// but it also handles some special cases like when renderer processes die.
-// THIS CLASS MUST NOT BE DESTROYED ON THE WEBKIT THREAD.
class DOMStorageDispatcherHost :
public base::RefCountedThreadSafe<DOMStorageDispatcherHost> {
public:
@@ -22,8 +28,9 @@ class DOMStorageDispatcherHost :
DOMStorageDispatcherHost(IPC::Message::Sender* message_sender,
WebKitContext*, WebKitThread*);
- // Only call from IO thread.
- bool OnMessageReceived(const IPC::Message& message);
+ // Only call from ResourceMessageFilter on the IO thread.
+ void Shutdown();
+ bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
// Send a message to the renderer process associated with our
// message_sender_ via the IO thread. May be called from any thread.
@@ -33,6 +40,37 @@ class DOMStorageDispatcherHost :
friend class base::RefCountedThreadSafe<DOMStorageDispatcherHost>;
~DOMStorageDispatcherHost();
+ // Message Handlers.
+ void OnNamespaceId(bool is_local_storage, IPC::Message* reply_msg);
+ void OnCloneNamespaceId(int64 namespace_id, IPC::Message* reply_msg);
+ void OnDerefNamespaceId(int64 namespace_id);
+ void OnStorageAreaId(int64 namespace_id, const string16& origin,
+ IPC::Message* reply_msg);
+ void OnLock(int64 storage_area_id, IPC::Message* reply_msg);
+ void OnUnlock(int64 storage_area_id);
+ void OnLength(int64 storage_area_id, IPC::Message* reply_msg);
+ void OnKey(int64 storage_area_id, unsigned index, IPC::Message* reply_msg);
+ void OnGetItem(int64 storage_area_id, const string16& key,
+ IPC::Message* reply_msg);
+ void OnSetItem(int64 storage_area_id, const string16& key,
+ const string16& value);
+ void OnRemoveItem(int64 storage_area_id, const string16& key);
+ void OnClear(int64 storage_area_id, IPC::Message* reply_msg);
+
+ // Get a WebStorageNamespace or WebStorageArea based from its ID. Only call
+ // on the WebKit thread.
+ WebKit::WebStorageArea* GetStorageArea(int64 id);
+ WebKit::WebStorageNamespace* GetStorageNamespace(int64 id);
+
+ // Add a WebStorageNamespace or WebStorageArea and get a new unique ID for
+ // it. Only call on the WebKit thread.
+ int64 AddStorageArea(WebKit::WebStorageArea* new_storage_area);
+ int64 AddStorageNamespace(WebKit::WebStorageNamespace* new_namespace);
+
+ // Get the path to the LocalStorage directory. Calculate it if we haven't
+ // already. Only call on the WebKit thread.
+ string16 GetLocalStoragePath();
+
// Data shared between renderer processes with the same profile.
scoped_refptr<WebKitContext> webkit_context_;
@@ -42,6 +80,32 @@ class DOMStorageDispatcherHost :
// Only set on the IO thread.
IPC::Message::Sender* message_sender_;
+ // The last used storage_area_id and storage_namespace_id's. Only use on the
+ // WebKit thread.
+ int64 last_storage_area_id_;
+ int64 last_storage_namespace_id_;
+
+ // Used to maintain a mapping between storage_area_id's used in IPC messages
+ // and the actual WebStorageArea instances. Only use on the WebKit thread.
+ typedef base::hash_map<int64, WebKit::WebStorageArea*> StorageAreaMap;
+ StorageAreaMap storage_area_map_;
+
+ // Mapping between storage_namespace_id's used in IPC messages and the
+ // WebStorageNamespace instances. Only use on the WebKit thread.
+ typedef base::hash_map<int64, WebKit::WebStorageNamespace*>
+ StorageNamespaceMap;
+ StorageNamespaceMap storage_namespace_map_;
+
+ // Has this dispatcher ever handled a message. If not, then we can skip
+ // the entire shutdown procedure. This is only set to true on the IO thread
+ // and must be true if we're reading it on the WebKit thread.
+ bool ever_used_;
+
+ // This is set once the Shutdown routine runs on the WebKit thread. Once
+ // set, we should not process any more messages because storage_area_map_
+ // and storage_namespace_map_ contain pointers to deleted objects.
+ bool shutdown_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageDispatcherHost);
};
diff --git a/chrome/browser/in_process_webkit/webkit_thread.cc b/chrome/browser/in_process_webkit/webkit_thread.cc
index 19cf65b..96384e9 100644
--- a/chrome/browser/in_process_webkit/webkit_thread.cc
+++ b/chrome/browser/in_process_webkit/webkit_thread.cc
@@ -10,13 +10,41 @@
#include "webkit/api/public/WebKit.h"
// This happens on the UI thread before the IO thread has been shut down.
-WebKitThread::WebKitThread() {
+WebKitThread::WebKitThread()
+ : io_message_loop_(ChromeThread::GetMessageLoop(ChromeThread::IO)) {
// The thread is started lazily by InitializeThread() on the IO thread.
}
// This happens on the UI thread after the IO thread has been shut down.
WebKitThread::~WebKitThread() {
+ // There's no good way to see if we're on the UI thread.
DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::IO));
+ DCHECK(!io_message_loop_);
+}
+
+void WebKitThread::Shutdown() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ DCHECK(io_message_loop_);
+
+ // TODO(jorlow): Start flushing LocalStorage?
+
+ AutoLock lock(io_message_loop_lock_);
+ io_message_loop_ = NULL;
+}
+
+bool WebKitThread::PostIOThreadTask(
+ const tracked_objects::Location& from_here, Task* task) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ {
+ AutoLock lock(io_message_loop_lock_);
+ if (io_message_loop_) {
+ io_message_loop_->PostTask(from_here, task);
+ return true;
+ }
+ }
+ delete task;
+ return false;
}
WebKitThread::InternalWebKitThread::InternalWebKitThread()
@@ -29,13 +57,12 @@ void WebKitThread::InternalWebKitThread::Init() {
webkit_client_ = new BrowserWebKitClientImpl;
DCHECK(webkit_client_);
WebKit::initialize(webkit_client_);
- // Don't do anything heavyweight here since this can block the IO thread from
- // executing (since InitializeThread() is called on the IO thread).
+ // If possible, post initialization tasks to this thread (rather than doing
+ // them now) so we don't block the IO thread any longer than we have to.
}
void WebKitThread::InternalWebKitThread::CleanUp() {
- // Don't do anything heavyweight here since this can block the IO thread from
- // executing (since the thread is shutdown from the IO thread).
+ // TODO(jorlow): Block on LocalStorage being 100% shut down.
DCHECK(webkit_client_);
WebKit::shutdown();
delete webkit_client_;
@@ -45,6 +72,7 @@ MessageLoop* WebKitThread::InitializeThread() {
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess))
return NULL;
+ DCHECK(io_message_loop_);
DCHECK(!webkit_thread_.get());
webkit_thread_.reset(new InternalWebKitThread);
bool started = webkit_thread_->Start();
diff --git a/chrome/browser/in_process_webkit/webkit_thread.h b/chrome/browser/in_process_webkit/webkit_thread.h
index 49ad7ac..8ab1113 100644
--- a/chrome/browser/in_process_webkit/webkit_thread.h
+++ b/chrome/browser/in_process_webkit/webkit_thread.h
@@ -35,6 +35,15 @@ class WebKitThread {
return webkit_thread_->message_loop();
}
+ // Called from the IO thread. Notifies us that it's no longer safe to post
+ // tasks to the IO thread.
+ void Shutdown();
+
+ // Post a task to the IO thread if we haven't yet been told to shut down.
+ // Only call from the WebKit thread.
+ bool PostIOThreadTask(const tracked_objects::Location& from_here,
+ Task* task);
+
private:
// Must be private so that we can carefully control its lifetime.
class InternalWebKitThread : public ChromeThread {
@@ -58,6 +67,11 @@ class WebKitThread {
// from the IO thread while the WebKit thread is not running.
scoped_ptr<InternalWebKitThread> webkit_thread_;
+ // A pointer to the IO message loop. This is nulled out when Shutdown() is
+ // called. Only access under the io_message_loop_lock_.
+ MessageLoop* io_message_loop_;
+ Lock io_message_loop_lock_;
+
DISALLOW_COPY_AND_ASSIGN(WebKitThread);
};
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index 35a47f0..9ac5b7f 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -259,6 +259,9 @@ void ResourceDispatcherHost::OnShutdown() {
// runs if the timer is still running the Task is deleted twice (once by
// the MessageLoop and the second time by RepeatingTimer).
update_load_states_timer_.Stop();
+ // Let the WebKit thread know the IO thread is going away soon and that it
+ // should prepare for its own shutdown soon after.
+ webkit_thread_->Shutdown();
}
bool ResourceDispatcherHost::HandleExternalProtocol(int request_id,
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index 41b0b35..f369191 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -169,6 +169,9 @@ ResourceMessageFilter::~ResourceMessageFilter() {
// This function should be called on the IO thread.
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ // Tell the DOM Storage dispatcher host to stop sending messages via us.
+ dom_storage_dispatcher_host_->Shutdown();
+
// Let interested observers know we are being deleted.
NotificationService::current()->Notify(
NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
@@ -244,7 +247,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) {
message, this, &msg_is_ok) ||
app_cache_dispatcher_host_->OnMessageReceived(
message, &msg_is_ok) ||
- dom_storage_dispatcher_host_->OnMessageReceived(message) ||
+ dom_storage_dispatcher_host_->OnMessageReceived(
+ message, &msg_is_ok) ||
audio_renderer_host_->OnMessageReceived(message, &msg_is_ok);
if (!handled) {