Blobs: Catching browser-process created Blobs in extension code.
This is a spinoff of https://codereview.chromium.org/266373006/, Patchset 11.
BUG=304290
Review URL: https://codereview.chromium.org/280393003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274268 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/extensions/browser/blob_holder.cc b/extensions/browser/blob_holder.cc
new file mode 100644
index 0000000..5f73953
--- /dev/null
+++ b/extensions/browser/blob_holder.cc
@@ -0,0 +1,85 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/blob_holder.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/logging.h"
+#include "content/public/browser/blob_handle.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace extensions {
+
+namespace {
+
+// Address to this variable used as the user data key.
+const int kBlobHolderUserDataKey = 0;
+}
+
+// static
+BlobHolder* BlobHolder::FromRenderProcessHost(
+ content::RenderProcessHost* render_process_host) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(render_process_host);
+ BlobHolder* existing = static_cast<BlobHolder*>(
+ render_process_host->GetUserData(&kBlobHolderUserDataKey));
+
+ if (existing)
+ return existing;
+
+ BlobHolder* new_instance = new BlobHolder(render_process_host);
+ render_process_host->SetUserData(&kBlobHolderUserDataKey, new_instance);
+ return new_instance;
+}
+
+BlobHolder::~BlobHolder() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
+
+void BlobHolder::HoldBlobReference(scoped_ptr<content::BlobHandle> blob) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(!ContainsBlobHandle(blob.get()));
+
+ held_blobs_.insert(
+ make_pair(blob->GetUUID(), make_linked_ptr(blob.release())));
+}
+
+BlobHolder::BlobHolder(content::RenderProcessHost* render_process_host)
+ : render_process_host_(render_process_host) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
+
+bool BlobHolder::ContainsBlobHandle(content::BlobHandle* handle) const {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ for (BlobHandleMultimap::const_iterator it = held_blobs_.begin();
+ it != held_blobs_.end();
+ ++it) {
+ if (it->second.get() == handle)
+ return true;
+ }
+
+ return false;
+}
+
+void BlobHolder::DropBlobs(const std::vector<std::string>& blob_uuids) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ for (std::vector<std::string>::const_iterator uuid_it = blob_uuids.begin();
+ uuid_it != blob_uuids.end();
+ ++uuid_it) {
+ BlobHandleMultimap::iterator it = held_blobs_.find(*uuid_it);
+
+ if (it != held_blobs_.end()) {
+ held_blobs_.erase(it);
+ } else {
+ DLOG(ERROR) << "Tried to release a Blob we don't have ownership to."
+ << "UUID: " << *uuid_it;
+ render_process_host_->ReceivedBadMessage();
+ }
+ }
+}
+
+} // namespace extensions
diff --git a/extensions/browser/blob_holder.h b/extensions/browser/blob_holder.h
new file mode 100644
index 0000000..9a1d8f51
--- /dev/null
+++ b/extensions/browser/blob_holder.h
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_BLOB_HOLDER_H_
+#define EXTENSIONS_BROWSER_BLOB_HOLDER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/supports_user_data.h"
+
+namespace content {
+class BlobHandle;
+class RenderProcessHost;
+}
+
+namespace extensions {
+
+class ExtensionMessageFilter;
+
+// Used for holding onto Blobs created into the browser process until a
+// renderer takes over ownership. This class operates on the UI thread.
+class BlobHolder : public base::SupportsUserData::Data {
+ public:
+ // Will create the BlobHolder if it doesn't already exist.
+ static BlobHolder* FromRenderProcessHost(
+ content::RenderProcessHost* render_process_host);
+
+ virtual ~BlobHolder();
+
+ // Causes BlobHolder to take ownership of |blob|.
+ void HoldBlobReference(scoped_ptr<content::BlobHandle> blob);
+
+ private:
+ typedef std::multimap<std::string, linked_ptr<content::BlobHandle> >
+ BlobHandleMultimap;
+
+ explicit BlobHolder(content::RenderProcessHost* render_process_host);
+
+ // BlobHolder will drop a blob handle for each element in blob_uuids.
+ // If caller wishes to drop multiple references to the same blob,
+ // |blob_uuids| may contain duplicate UUIDs.
+ void DropBlobs(const std::vector<std::string>& blob_uuids);
+ friend class ExtensionMessageFilter;
+
+ bool ContainsBlobHandle(content::BlobHandle* handle) const;
+
+ // A reference to the owner of this class.
+ content::RenderProcessHost* render_process_host_;
+
+ BlobHandleMultimap held_blobs_;
+
+ DISALLOW_COPY_AND_ASSIGN(BlobHolder);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_BLOB_HOLDER_H_
diff --git a/extensions/browser/extension_function.cc b/extensions/browser/extension_function.cc
index 7d092053..15e92cc 100644
--- a/extensions/browser/extension_function.cc
+++ b/extensions/browser/extension_function.cc
@@ -386,18 +386,39 @@
delegate_->OnSendResponse(this, success, bad_message_);
else
SendResponseImpl(success);
+
+ if (!transferred_blob_uuids_.empty()) {
+ DCHECK(!delegate_) << "Blob transfer not supported with test delegate.";
+ GetIPCSender()->Send(
+ new ExtensionMsg_TransferBlobs(transferred_blob_uuids_));
+ }
+}
+
+void UIThreadExtensionFunction::SetTransferredBlobUUIDs(
+ const std::vector<std::string>& blob_uuids) {
+ DCHECK(transferred_blob_uuids_.empty()); // Should only be called once.
+ transferred_blob_uuids_ = blob_uuids;
}
void UIThreadExtensionFunction::WriteToConsole(
content::ConsoleMessageLevel level,
const std::string& message) {
- if (render_view_host_) {
- render_view_host_->Send(new ExtensionMsg_AddMessageToConsole(
- render_view_host_->GetRoutingID(), level, message));
- } else {
- render_frame_host_->Send(new ExtensionMsg_AddMessageToConsole(
- render_frame_host_->GetRoutingID(), level, message));
- }
+ GetIPCSender()->Send(
+ new ExtensionMsg_AddMessageToConsole(GetRoutingID(), level, message));
+}
+
+IPC::Sender* UIThreadExtensionFunction::GetIPCSender() {
+ if (render_view_host_)
+ return render_view_host_;
+ else
+ return render_frame_host_;
+}
+
+int UIThreadExtensionFunction::GetRoutingID() {
+ if (render_view_host_)
+ return render_view_host_->GetRoutingID();
+ else
+ return render_frame_host_->GetRoutingID();
}
IOThreadExtensionFunction::IOThreadExtensionFunction()
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h
index 0116193..aef934a 100644
--- a/extensions/browser/extension_function.h
+++ b/extensions/browser/extension_function.h
@@ -44,6 +44,10 @@
class QuotaLimitHeuristic;
}
+namespace IPC {
+class Sender;
+}
+
#ifdef NDEBUG
#define EXTENSION_FUNCTION_VALIDATE(test) \
do { \
@@ -441,6 +445,9 @@
virtual void SendResponse(bool success) OVERRIDE;
+ // Sets the Blob UUIDs whose ownership is being transferred to the renderer.
+ void SetTransferredBlobUUIDs(const std::vector<std::string>& blob_uuids);
+
// The dispatcher that will service this extension function call.
base::WeakPtr<extensions::ExtensionFunctionDispatcher> dispatcher_;
@@ -460,9 +467,16 @@
virtual void Destruct() const OVERRIDE;
+ // TODO(tommycli): Remove once RenderViewHost is gone.
+ IPC::Sender* GetIPCSender();
+ int GetRoutingID();
+
scoped_ptr<RenderHostTracker> tracker_;
DelegateForTests* delegate_;
+
+ // The blobs transferred to the renderer process.
+ std::vector<std::string> transferred_blob_uuids_;
};
// Extension functions that run on the IO thread. This type of function avoids
diff --git a/extensions/browser/extension_message_filter.cc b/extensions/browser/extension_message_filter.cc
index 3cf93f0..e25480d 100644
--- a/extensions/browser/extension_message_filter.cc
+++ b/extensions/browser/extension_message_filter.cc
@@ -7,6 +7,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
+#include "extensions/browser/blob_holder.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_function_dispatcher.h"
#include "extensions/browser/extension_system.h"
@@ -44,6 +45,7 @@
case ExtensionHostMsg_RemoveFilteredListener::ID:
case ExtensionHostMsg_ShouldSuspendAck::ID:
case ExtensionHostMsg_SuspendAck::ID:
+ case ExtensionHostMsg_TransferBlobsAck::ID:
*thread = BrowserThread::UI;
break;
default:
@@ -70,6 +72,8 @@
OnExtensionShouldSuspendAck)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_SuspendAck,
OnExtensionSuspendAck)
+ IPC_MESSAGE_HANDLER(ExtensionHostMsg_TransferBlobsAck,
+ OnExtensionTransferBlobsAck)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_GenerateUniqueID,
OnExtensionGenerateUniqueID)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_ResumeRequests,
@@ -167,6 +171,14 @@
process_manager->OnSuspendAck(extension_id);
}
+void ExtensionMessageFilter::OnExtensionTransferBlobsAck(
+ const std::vector<std::string>& blob_uuids) {
+ RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
+ if (!process)
+ return;
+ BlobHolder::FromRenderProcessHost(process)->DropBlobs(blob_uuids);
+}
+
void ExtensionMessageFilter::OnExtensionGenerateUniqueID(int* unique_id) {
static int next_unique_id = 0;
*unique_id = ++next_unique_id;
diff --git a/extensions/browser/extension_message_filter.h b/extensions/browser/extension_message_filter.h
index 26060c5..3305794 100644
--- a/extensions/browser/extension_message_filter.h
+++ b/extensions/browser/extension_message_filter.h
@@ -6,6 +6,7 @@
#define EXTENSIONS_BROWSER_EXTENSION_MESSAGE_FILTER_H_
#include <string>
+#include <vector>
#include "base/compiler_specific.h"
#include "base/macros.h"
@@ -65,6 +66,7 @@
void OnExtensionShouldSuspendAck(const std::string& extension_id,
int sequence_id);
void OnExtensionSuspendAck(const std::string& extension_id);
+ void OnExtensionTransferBlobsAck(const std::vector<std::string>& blob_uuids);
// Message handlers on the IO thread.
void OnExtensionGenerateUniqueID(int* unique_id);