| Index: blimp/engine/renderer/blob_channel_sender_proxy.cc
|
| diff --git a/blimp/engine/renderer/blob_channel_sender_proxy.cc b/blimp/engine/renderer/blob_channel_sender_proxy.cc
|
| index 8b689d36c73dd840878105bb72a926845ebe97be..08ec8f3f0f1c71f4303d1e0da9252e4ccd7f5587 100644
|
| --- a/blimp/engine/renderer/blob_channel_sender_proxy.cc
|
| +++ b/blimp/engine/renderer/blob_channel_sender_proxy.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "blimp/engine/renderer/blob_channel_sender_proxy.h"
|
|
|
| +#include "blimp/common/blob_cache/id_util.h"
|
| #include "content/public/common/service_registry.h"
|
| #include "content/public/renderer/render_thread.h"
|
|
|
| @@ -19,30 +20,109 @@ mojom::BlobChannelPtr GetConnectedBlobChannel() {
|
| return blob_channel_ptr;
|
| }
|
|
|
| +// Manages the creation and lifetime of Mojo shared memory buffers for blobs.
|
| +// Cleans up the shared memory state when deleted.
|
| +// Caller is responsible for ensuring that |this| is not deleted until the
|
| +// remote side has acknowledged that it is finished using the buffer.
|
| +class SharedMemoryBlob {
|
| + public:
|
| + explicit SharedMemoryBlob(BlobDataPtr data) {
|
| + mojo::ScopedSharedBufferHandle local_handle;
|
| + MojoResult result =
|
| + mojo::CreateSharedBuffer(NULL, data->data.size(), &local_handle);
|
| + CHECK_EQ(MOJO_RESULT_OK, result)
|
| + << "Mojo error when creating shared buffer: " << result;
|
| +
|
| + result = mojo::MapBuffer(local_handle.get(), 0, data->data.size(),
|
| + &mapped_data_, MOJO_MAP_BUFFER_FLAG_NONE);
|
| + CHECK_EQ(MOJO_RESULT_OK, result)
|
| + << "Mojo error when memory mapping shared buffer: " << result;
|
| + memcpy(mapped_data_, data->data.data(), data->data.size());
|
| +
|
| + // Create read-only handle for browser-side consumption.
|
| + MojoDuplicateBufferHandleOptions options{
|
| + sizeof(MojoDuplicateBufferHandleOptions),
|
| + MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY};
|
| + result =
|
| + mojo::DuplicateBuffer(local_handle.get(), &options, &remote_handle_);
|
| + CHECK_EQ(MOJO_RESULT_OK, result)
|
| + << "Mojo error when creating read-only buffer handle.";
|
| + DCHECK(remote_handle_.is_valid());
|
| + }
|
| +
|
| + ~SharedMemoryBlob() {
|
| + MojoResult result = mojo::UnmapBuffer(mapped_data_);
|
| + CHECK_EQ(MOJO_RESULT_OK, result);
|
| + }
|
| +
|
| + mojo::ScopedSharedBufferHandle take_remote_handle() {
|
| + return std::move(remote_handle_);
|
| + }
|
| +
|
| + private:
|
| + // Pointer to shared memory buffer.
|
| + void* mapped_data_;
|
| +
|
| + // Handle to be passed to the remote end of the BlobChannel Mojo service.
|
| + mojo::ScopedSharedBufferHandle remote_handle_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SharedMemoryBlob);
|
| +};
|
| +
|
| +void PutComplete(std::unique_ptr<SharedMemoryBlob>) {
|
| + // Allow the blob to go out of scope and be deleted.
|
| +}
|
| +
|
| } // namespace
|
|
|
| BlobChannelSenderProxy::BlobChannelSenderProxy()
|
| - : blob_channel_(GetConnectedBlobChannel()) {}
|
| + : BlobChannelSenderProxy(GetConnectedBlobChannel()) {}
|
|
|
| BlobChannelSenderProxy::~BlobChannelSenderProxy() {}
|
|
|
| +BlobChannelSenderProxy::BlobChannelSenderProxy(
|
| + mojom::BlobChannelPtr blob_channel)
|
| + : blob_channel_(std::move(blob_channel)) {}
|
| +
|
| bool BlobChannelSenderProxy::IsInEngineCache(const std::string& id) const {
|
| return replication_state_.find(id) != replication_state_.end();
|
| }
|
|
|
| bool BlobChannelSenderProxy::IsInClientCache(const std::string& id) const {
|
| - return replication_state_.find(id)->second;
|
| + auto found = replication_state_.find(id);
|
| + return found != replication_state_.end() && found->second;
|
| }
|
|
|
| void BlobChannelSenderProxy::PutBlob(const BlobId& id, BlobDataPtr data) {
|
| - DCHECK(!IsInEngineCache(id));
|
| + if (IsInEngineCache(id)) {
|
| + DLOG(ERROR) << "Redundant blob put attempted: " << BlobIdToString(id);
|
| + return;
|
| + }
|
| +
|
| + size_t size = data->data.size();
|
| + if (size == 0) {
|
| + DLOG(FATAL) << "Zero length blob requested: " << BlobIdToString(id);
|
| + return;
|
| + }
|
|
|
| replication_state_[id] = false;
|
| - blob_channel_->PutBlob(id, data->data);
|
| + std::unique_ptr<SharedMemoryBlob> shared_mem_blob(
|
| + new SharedMemoryBlob(std::move(data)));
|
| + blob_channel_->PutBlob(
|
| + id, shared_mem_blob->take_remote_handle(), size,
|
| + base::Bind(&PutComplete, base::Passed(std::move(shared_mem_blob))));
|
| }
|
|
|
| void BlobChannelSenderProxy::DeliverBlob(const std::string& id) {
|
| - DCHECK(!IsInClientCache(id));
|
| + if (!IsInEngineCache(id)) {
|
| + DLOG(ERROR) << "Attempted to deliver an invalid blob: "
|
| + << BlobIdToString(id);
|
| + return;
|
| + }
|
| + if (IsInClientCache(id)) {
|
| + DLOG(ERROR) << "Blob is already in the remote cache:" << BlobIdToString(id);
|
| + return;
|
| + }
|
|
|
| // We assume that the client will have the blob if we push it.
|
| // TODO(kmarshall): Revisit this assumption when asynchronous blob transport
|
|
|