| Index: content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.cc
|
| diff --git a/content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.cc b/content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..42fc8eb087299c64a2251ee0ce1d210cb959cad5
|
| --- /dev/null
|
| +++ b/content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.cc
|
| @@ -0,0 +1,779 @@
|
| +// Copyright 2015 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 "content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.h"
|
| +
|
| +#include <chrono>
|
| +
|
| +#include "base/memory/shared_memory.h"
|
| +#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
|
| +#include "chrome/browser/chromeos/file_system_provider/request_manager.h"
|
| +#include "chrome/browser/chromeos/file_system_provider/file_system_plugin/plugin_service.h"
|
| +#include "chrome/browser/profiles/profile_manager.h"
|
| +#include "content/public/browser/browser_ppapi_host.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "ppapi/c/pp_errors.h"
|
| +#include "ppapi/host/ppapi_host.h"
|
| +#include "ppapi/proxy/ppapi_messages.h"
|
| +
|
| +using namespace chromeos::file_system_provider;
|
| +using content::BrowserThread;
|
| +using ppapi::host::HostMessageContext;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +// TODO(sabin): find a way to get the size of the stream reader internal
|
| +// buffer from the backend
|
| +// Size of the stream reader internal buffer. At most this number of bytes will
|
| +// be read ahead of the requested data.
|
| +const uint32_t kReaderBufferSize = 512 * 1024; // 512KB.
|
| +
|
| +// Size of the stream writer internal buffer. At most this number of bytes will
|
| +// be postponed for writing.
|
| +const uint32_t kWriterBufferSize = 512 * 1024; // 512KB.
|
| +
|
| +// The number of requests that can be buffered
|
| +const uint32_t kMaximumCachedReplies = 10;
|
| +
|
| +RequestType PP_OperationToRequestType(int32_t operation_type) {
|
| + switch (operation_type) {
|
| + case PP_OperationType_ABORT:
|
| + return ABORT;
|
| + case PP_OperationType_ADDWATCHER:
|
| + return ADD_WATCHER;
|
| + case PP_OperationType_CLOSEFILE:
|
| + return CLOSE_FILE;
|
| + case PP_OperationType_COPYENTRY:
|
| + return COPY_ENTRY;
|
| + case PP_OperationType_CREATEDIRECTORY:
|
| + return CREATE_DIRECTORY;
|
| + case PP_OperationType_CREATEFILE:
|
| + return CREATE_FILE;
|
| + case PP_OperationType_DELETEENTRY:
|
| + return DELETE_ENTRY;
|
| + case PP_OperationType_GETMETADATA:
|
| + return GET_METADATA;
|
| + case PP_OperationType_MOVEENTRY:
|
| + return MOVE_ENTRY;
|
| + case PP_OperationType_OPENFILE:
|
| + return OPEN_FILE;
|
| + case PP_OperationType_READDIRECTORY:
|
| + return READ_DIRECTORY;
|
| + case PP_OperationType_READFILE:
|
| + return READ_FILE;
|
| + case PP_OperationType_REMOVEWATCHER:
|
| + return REMOVE_WATCHER;
|
| + case PP_OperationType_TRUNCATEENTRY:
|
| + return TRUNCATE;
|
| + case PP_OperationType_UNMOUNT:
|
| + return REQUEST_UNMOUNT;
|
| + case PP_OperationType_WRITEFILE:
|
| + return WRITE_FILE;
|
| + case PP_OperationType_NONE:
|
| + default:
|
| + break;
|
| + }
|
| + NOTREACHED();
|
| + return ABORT;
|
| +}
|
| +
|
| +PP_OperationType_Dev RequestTypeToOperationType(int32_t operation_type) {
|
| + switch (operation_type) {
|
| + case ABORT:
|
| + return PP_OperationType_ABORT;
|
| + case ADD_WATCHER:
|
| + return PP_OperationType_ADDWATCHER;
|
| + case CLOSE_FILE:
|
| + return PP_OperationType_CLOSEFILE;
|
| + case COPY_ENTRY:
|
| + return PP_OperationType_COPYENTRY;
|
| + case CREATE_DIRECTORY:
|
| + return PP_OperationType_CREATEDIRECTORY;
|
| + case CREATE_FILE:
|
| + return PP_OperationType_CREATEFILE;
|
| + case DELETE_ENTRY:
|
| + return PP_OperationType_DELETEENTRY;
|
| + case GET_METADATA:
|
| + return PP_OperationType_GETMETADATA;
|
| + case MOVE_ENTRY:
|
| + return PP_OperationType_MOVEENTRY;
|
| + case OPEN_FILE:
|
| + return PP_OperationType_OPENFILE;
|
| + case READ_DIRECTORY:
|
| + return PP_OperationType_READDIRECTORY;
|
| + case READ_FILE:
|
| + return PP_OperationType_READFILE;
|
| + case REMOVE_WATCHER:
|
| + return PP_OperationType_REMOVEWATCHER;
|
| + case TRUNCATE:
|
| + return PP_OperationType_TRUNCATEENTRY;
|
| + case REQUEST_UNMOUNT:
|
| + return PP_OperationType_UNMOUNT;
|
| + case WRITE_FILE:
|
| + return PP_OperationType_WRITEFILE;
|
| + default:
|
| + break;
|
| + }
|
| + NOTREACHED();
|
| + return PP_OperationType_NONE;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +PepperFilesystemProviderBackendChromeOS::
|
| + ProvidedFilesystemInfo::ProvidedFilesystemInfo()
|
| + :filesystem_id("none"),
|
| + display_name("none"),
|
| + plugin_name("none"),
|
| + writable(false),
|
| + opened_files_limit(0) {
|
| +}
|
| +PepperFilesystemProviderBackendChromeOS::ShmBuffer::ShmBuffer(
|
| + uint32_t size, scoped_ptr<base::SharedMemory> shm)
|
| + : size(size),shm(shm.Pass()) {
|
| + DCHECK(this->shm);
|
| +}
|
| +
|
| +PepperFilesystemProviderBackendChromeOS::ShmBuffer::~ShmBuffer() {
|
| +
|
| +}
|
| +
|
| +PepperFilesystemProviderBackendChromeOS::
|
| + ShmChannelController::ShmChannelController(
|
| + uint32_t size, FlushRequestCallback callback)
|
| + : max_size(size),
|
| + ready(true),
|
| + callback(callback){
|
| +}
|
| +PepperFilesystemProviderBackendChromeOS::
|
| + ShmChannelController::~ShmChannelController() {
|
| +}
|
| +
|
| +bool PepperFilesystemProviderBackendChromeOS::
|
| + ShmChannelController::EnqueueRequest(
|
| + scoped_ptr<base::ListValue> response) {
|
| + // If channel ready send it straight away
|
| + if(ready) {
|
| + ready = !callback.Run(response.Pass());
|
| + if(!ready)
|
| + return true;
|
| + }
|
| + // If channel is not ready or failed to send
|
| + // cache the request
|
| + if(size() + 1 > max_size)
|
| + return false;
|
| + replies.push_back( response.Pass() );
|
| + return true;
|
| +}
|
| +
|
| +bool PepperFilesystemProviderBackendChromeOS::
|
| + ShmChannelController::PushNextRequest() {
|
| + // Try and send the request
|
| + scoped_ptr<base::ListValue> response;
|
| + while (size()>0 && ready ) {
|
| + response.reset(replies.front());
|
| + replies.weak_erase(replies.begin());
|
| + ready = !callback.Run(response.Pass());
|
| + }
|
| + return !ready;
|
| +}
|
| +
|
| +bool
|
| +PepperFilesystemProviderBackendChromeOS::
|
| + ShmChannelController::AckLastPushedRequest() {
|
| + return ready = true;
|
| +}
|
| +
|
| +uint32_t PepperFilesystemProviderBackendChromeOS::
|
| + ShmChannelController::size() {
|
| + return replies.size();
|
| +}
|
| +
|
| +
|
| +
|
| +PepperFilesystemProviderBackendChromeOS::
|
| +PepperFilesystemProviderBackendChromeOS(
|
| + content::BrowserPpapiHost *host,
|
| + PP_Instance instance,
|
| + PP_Resource resource)
|
| + : mounted_(false),
|
| + host_(host ? host->GetPpapiHost() : nullptr),
|
| + resource_(resource),
|
| + write_channel_controller_(new ShmChannelController(
|
| + kMaximumCachedReplies,
|
| + base::Bind(
|
| + &PepperFilesystemProviderBackendChromeOS::
|
| + FlushRequest,
|
| + base::Unretained(this)))),
|
| + weak_factory_(this) {
|
| +
|
| + filesystem_info_.plugin_name = std::string("Plugin_") +
|
| + std::to_string(static_cast<size_t>(instance));
|
| +}
|
| +
|
| +PepperFilesystemProviderBackendChromeOS::
|
| +~PepperFilesystemProviderBackendChromeOS() {
|
| + // Unregister the filesystem if state indicates
|
| + // that we have a mounted filesystem
|
| + if (mounted_) {
|
| + // Unregister any registered event from the PluginEventRouter
|
| + UnregisterFilesystemListenedOperations();
|
| + // Unregister the filesystem backend on the
|
| + // proper thread from Service
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + base::IgnoreResult(
|
| + &PepperFilesystemProviderBackendChromeOS::
|
| + UnregisterFilesystemOnUI),
|
| + filesystem_info_
|
| + )
|
| + );
|
| + }
|
| +}
|
| +
|
| +// Called when PpapiHostMsg_FilesystemProvider_Mount is received
|
| +// Forwards request to RegisterFilesystemOnUI
|
| +// Response is sent from MountReplyOnIO
|
| +int32_t PepperFilesystemProviderBackendChromeOS::SendMountRequest(
|
| + ppapi::host::HostMessageContext *context,
|
| + const base::ListValue& request) {
|
| + using content::filesystem_provider_internal::MountOperationTranslator;
|
| +
|
| + base::File::Error status = base::File::FILE_OK;
|
| + if (mounted_)
|
| + status = base::File::FILE_ERROR_EXISTS;
|
| +
|
| + scoped_ptr<MountOperationTranslator> mount_info =
|
| + MountOperationTranslator::PopulateFromResponse(request);
|
| + if ( !mount_info.get() )
|
| + status = base::File::FILE_ERROR_FAILED;
|
| +
|
| + // Stop and send failure back to the plugin
|
| + if (status!=base::File::FILE_OK) {
|
| + MountReplyOnIO(
|
| + context->MakeReplyMessageContext(),
|
| + filesystem_info_, base::File::FILE_ERROR_EXISTS);
|
| + return PP_OK_COMPLETIONPENDING;
|
| + }
|
| + // Populate the desired filesystem configuration
|
| + ProvidedFilesystemInfo filesystem_info;
|
| + filesystem_info.writable = mount_info->writable;
|
| + filesystem_info.display_name = mount_info->display_name;
|
| + filesystem_info.plugin_name = filesystem_info_.plugin_name;
|
| + filesystem_info.filesystem_id = mount_info->file_system_id;
|
| + filesystem_info.opened_files_limit = mount_info->opened_files_limit;
|
| + // Change thread to create the filesystem backend on the
|
| + // UI thread. The result of this action is to be interpreted
|
| + // on the IO thread.
|
| + BrowserThread::PostTaskAndReplyWithResult(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + // This creates a filesystem backend owned by the Service
|
| + // entity
|
| + &PepperFilesystemProviderBackendChromeOS::RegisterFilesystemOnUI,
|
| + filesystem_info),
|
| + // This is called after the above returns to interpret result
|
| + base::Bind(
|
| + &PepperFilesystemProviderBackendChromeOS::MountReplyOnIO,
|
| + weak_factory_.GetWeakPtr(),
|
| + context->MakeReplyMessageContext(),
|
| + filesystem_info
|
| + )
|
| + );
|
| + return PP_OK_COMPLETIONPENDING;
|
| +}
|
| +
|
| +// Called when PpapiHostMsg_FilesystemProvider_Unmount is received
|
| +// Forwards request to UnregisterFilesystemOnUI
|
| +// Response is sent from MountReplyOnIO
|
| +int32_t PepperFilesystemProviderBackendChromeOS::SendUnmountRequest(
|
| + ppapi::host::HostMessageContext *context, const std::string& fsid) {
|
| +
|
| + if(!mounted_) {
|
| + return PP_ERROR_FAILED;
|
| + }
|
| +
|
| + // Remove registered events from PluginEventRouter
|
| + UnregisterFilesystemListenedOperations();
|
| +
|
| + BrowserThread::PostTaskAndReplyWithResult(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &PepperFilesystemProviderBackendChromeOS::UnregisterFilesystemOnUI,
|
| + filesystem_info_),
|
| + base::Bind( &PepperFilesystemProviderBackendChromeOS::UnmountReplyOnIO,
|
| + weak_factory_.GetWeakPtr(),
|
| + context->MakeReplyMessageContext())
|
| + );
|
| + return PP_OK_COMPLETIONPENDING;
|
| +}
|
| +
|
| +int32_t PepperFilesystemProviderBackendChromeOS::OnPluginResponse(
|
| + ppapi::host::HostMessageContext* context,
|
| + const base::ListValue& plugin_response) {
|
| + scoped_ptr<base::ListValue> response( plugin_response.DeepCopy() );
|
| +
|
| + if (!response.get() ||
|
| + !mounted_)
|
| + return PP_ERROR_FAILED;
|
| +
|
| + bool status;
|
| + int operation_type = PP_OperationType_NONE;
|
| + if (!PreprocessMessage(*response, status, operation_type))
|
| + return PP_ERROR_FAILED;
|
| + if ( status ) {// success
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + base::IgnoreResult(
|
| + &PepperFilesystemProviderBackendChromeOS::
|
| + OnSuccessResponse),
|
| + operation_type,
|
| + filesystem_info_,
|
| + base::Passed(response.Pass()))
|
| + );
|
| + } else { // failure
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + base::IgnoreResult(
|
| + &PepperFilesystemProviderBackendChromeOS::
|
| + OnErrorResponse),
|
| + filesystem_info_,
|
| + base::Passed(response.Pass()))
|
| + );
|
| + }
|
| +
|
| + return PP_OK;
|
| +}
|
| +
|
| +// Sends next cached request if there is any pending
|
| +int32_t PepperFilesystemProviderBackendChromeOS::OnPluginWriteAck(
|
| + ppapi::host::HostMessageContext* ) {
|
| + write_channel_controller_->AckLastPushedRequest();
|
| + write_channel_controller_->PushNextRequest();
|
| + return PP_OK;
|
| +}
|
| +
|
| +int32_t PepperFilesystemProviderBackendChromeOS::OnPluginNotification(
|
| + ppapi::host::HostMessageContext* context, const base::ListValue& args) {
|
| + scoped_ptr<base::ListValue> message(args.DeepCopy());
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &PepperFilesystemProviderBackendChromeOS::
|
| + SendNotificationOnUI,
|
| + filesystem_info_, base::Passed(message.Pass())
|
| + )
|
| + );
|
| + return PP_OK;
|
| +}
|
| +
|
| +void OnNotifyCompleted(base::File::Error /*result*/) {}
|
| +
|
| +void PepperFilesystemProviderBackendChromeOS::SendNotificationOnUI(
|
| + const ProvidedFilesystemInfo& file_system_info,
|
| + scoped_ptr<base::ListValue> args) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| +
|
| + PluginService *fs_service = PluginService::Get(
|
| + ProfileManager::GetActiveUserProfile());
|
| + DCHECK(fs_service);
|
| +
|
| + ProvidedFileSystemAdapter* fs_backend =
|
| + fs_service->GetProvidedFileSystemAdapter(
|
| + file_system_info.plugin_name,
|
| + file_system_info.filesystem_id);
|
| + if (!fs_backend)
|
| + return;
|
| + fs_backend->PushChangeNotificationResponse(args.Pass(),
|
| + base::Bind(OnNotifyCompleted));
|
| +}
|
| +
|
| +// Add all events to the PluginEventRouter list of dispatchable events
|
| +void PepperFilesystemProviderBackendChromeOS::
|
| +RegisterFilesystemListenedOperations() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + std::vector<RequestType> operations = {
|
| + REQUEST_UNMOUNT, GET_METADATA, READ_DIRECTORY, OPEN_FILE, CLOSE_FILE,
|
| + READ_FILE, CREATE_DIRECTORY, DELETE_ENTRY, CREATE_FILE, COPY_ENTRY,
|
| + MOVE_ENTRY, TRUNCATE, WRITE_FILE, ABORT, ADD_WATCHER, REMOVE_WATCHER
|
| + };
|
| + PluginOperationRouter *router = PluginOperationRouter::GetInstance();
|
| + if (router!=nullptr)
|
| + router->AddOperationsForListener( operations, this,
|
| + filesystem_info_.plugin_name );
|
| +}
|
| +using chromeos::file_system_provider::READ_DIRECTORY;
|
| +// Remove all events from the PluginEventRouter list of dispatchable events
|
| +void PepperFilesystemProviderBackendChromeOS::
|
| +UnregisterFilesystemListenedOperations() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + std::vector<RequestType> operations = {
|
| + REQUEST_UNMOUNT, GET_METADATA, READ_DIRECTORY, OPEN_FILE, CLOSE_FILE,
|
| + READ_FILE, CREATE_DIRECTORY, DELETE_ENTRY, CREATE_FILE, COPY_ENTRY,
|
| + MOVE_ENTRY, TRUNCATE, WRITE_FILE, ABORT, ADD_WATCHER, REMOVE_WATCHER
|
| + };
|
| + PluginOperationRouter *router = PluginOperationRouter::GetInstance();
|
| + if (router!=nullptr)
|
| + router->RemoveOperationsForListener(operations,
|
| + filesystem_info_.plugin_name);
|
| +}
|
| +
|
| +// Static
|
| +// Responsible with the creations and registration of a new provided filesystem
|
| +base::File::Error PepperFilesystemProviderBackendChromeOS::
|
| +RegisterFilesystemOnUI(
|
| + ProvidedFilesystemInfo filesystem_info)
|
| +{
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| +
|
| + PluginService *fs_service = PluginService::Get(
|
| + ProfileManager::GetActiveUserProfile());
|
| + DCHECK(fs_service);
|
| +
|
| + chromeos::file_system_provider::MountOptions options(
|
| + filesystem_info.filesystem_id, filesystem_info.display_name);
|
| +
|
| + // TODO(sabin): add support for watchers
|
| + options.supports_notify_tag = false;
|
| + options.writable = filesystem_info.writable;
|
| + options.opened_files_limit = filesystem_info.opened_files_limit;
|
| +
|
| + base::File::Error error = fs_service->MountFileSystem(
|
| + filesystem_info.plugin_name,
|
| + options);
|
| +
|
| + return error; // This will be interpreted by MountReplyOnIO
|
| +}
|
| +
|
| +// Sends feedback to the plugin
|
| +// and sets state
|
| +void PepperFilesystemProviderBackendChromeOS::MountReplyOnIO(
|
| + ppapi::host::ReplyMessageContext reply_msg,
|
| + ProvidedFilesystemInfo filesystem_info,
|
| + base::File::Error err) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + // If an error occured or we cannot initialize the shared memory
|
| + if ( err != base::File::FILE_OK ||
|
| + !InitializeMemoryBuffer()) {
|
| + reply_msg.params.set_result(PP_ERROR_FAILED);
|
| + host_->SendReply(
|
| + reply_msg,
|
| + PpapiPluginMsg_FilesystemProvider_MountReply()
|
| + );
|
| + // Undo the registration
|
| + if (err==base::File::FILE_OK) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + base::IgnoreResult(
|
| + &PepperFilesystemProviderBackendChromeOS::
|
| + UnregisterFilesystemOnUI),
|
| + filesystem_info
|
| + )
|
| + );
|
| + }
|
| + return;
|
| + }
|
| +
|
| + RegisterFilesystemListenedOperations();
|
| + mounted_ = true;
|
| + filesystem_info_.writable = filesystem_info.writable;
|
| + filesystem_info_.display_name = filesystem_info.display_name;
|
| + filesystem_info_.filesystem_id = filesystem_info.filesystem_id;
|
| + filesystem_info_.opened_files_limit = filesystem_info.opened_files_limit;
|
| +
|
| +
|
| + reply_msg.params.set_result(PP_OK);
|
| + host_->SendReply(
|
| + reply_msg,
|
| + PpapiPluginMsg_FilesystemProvider_MountReply()
|
| + );
|
| +}
|
| +
|
| +//static
|
| +// Responsible with removal of the filesystem backend
|
| +base::File::Error PepperFilesystemProviderBackendChromeOS::
|
| +UnregisterFilesystemOnUI(
|
| + ProvidedFilesystemInfo filesystem_info) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| +
|
| + PluginService *fs_service = PluginService::Get(
|
| + ProfileManager::GetActiveUserProfile());
|
| + DCHECK(fs_service);
|
| +
|
| + base::File::Error err = fs_service->UnmountFileSystem(
|
| + filesystem_info.plugin_name,
|
| + filesystem_info.filesystem_id,
|
| + chromeos::file_system_provider::PluginService::UNMOUNT_REASON_USER );
|
| +
|
| + return err;
|
| +}
|
| +
|
| +// Sends feedback to the plugin
|
| +// and resets state
|
| +void PepperFilesystemProviderBackendChromeOS::UnmountReplyOnIO(
|
| + ppapi::host::ReplyMessageContext reply_msg, base::File::Error err) {
|
| +
|
| + reply_msg.params.set_result(PP_OK);
|
| + // Unregister all events
|
| + UnregisterFilesystemListenedOperations();
|
| +
|
| + mounted_ = false;
|
| + // Send result to the plugin
|
| + host_->SendReply(
|
| + reply_msg,
|
| + PpapiPluginMsg_FilesystemProvider_UnmountReply()
|
| + );
|
| +}
|
| +
|
| +void PepperFilesystemProviderBackendChromeOS::OnDispatchOperationRequest(
|
| + RequestType operation_type, scoped_ptr<base::ListValue> request) {
|
| + if ( operation_type==WRITE_FILE ) {
|
| + // Handle write to filesystem
|
| + // Put the chunk into the shared memory buffer or cache it
|
| + // if channel is not free
|
| + // TODO(sabin): Send error back to backend if this fails
|
| + write_channel_controller_->EnqueueRequest(request.Pass());
|
| + } else {
|
| + //TODO(sabin): Remove this when done testing
|
| + if(operation_type==OPEN_FILE)
|
| + time_stamp_=std::chrono::system_clock::now();
|
| + else if(operation_type==CLOSE_FILE) {
|
| + std::chrono::duration<double> elapsed_seconds =
|
| + std::chrono::system_clock::now()-time_stamp_;
|
| + LOG(ERROR) <<"Read/Write operation time: "<< elapsed_seconds.count()<<
|
| + " seconds";
|
| + }
|
| + host_->SendUnsolicitedReply(
|
| + resource_,
|
| + PpapiPluginMsg_FilesystemProvider_OperationRequest(
|
| + RequestTypeToOperationType(operation_type),
|
| + *request)
|
| + );
|
| + }
|
| +}
|
| +
|
| +// Transforms messages that are received from
|
| +// the plugin in response of filesystem operations and sends
|
| +// them back to the filesystem backend.
|
| +int32_t PepperFilesystemProviderBackendChromeOS::OnSuccessResponse(
|
| + int operation,
|
| + const ProvidedFilesystemInfo& filesystem_info,
|
| + scoped_ptr<base::ListValue> response ) {
|
| +
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + PluginService *fs_service = PluginService::Get(
|
| + ProfileManager::GetActiveUserProfile());
|
| + DCHECK(fs_service);
|
| +
|
| + ProvidedFileSystemAdapter* fs_backend =
|
| + fs_service->GetProvidedFileSystemAdapter(
|
| + filesystem_info.plugin_name,
|
| + filesystem_info.filesystem_id);
|
| +
|
| + if (fs_backend==nullptr)
|
| + return PP_ERROR_FAILED;
|
| + fs_backend->PushSuccessResponse( PP_OperationToRequestType(operation),
|
| + response.Pass());
|
| +
|
| + return PP_OK;
|
| +}
|
| +
|
| +int32_t PepperFilesystemProviderBackendChromeOS::OnErrorResponse(
|
| + const ProvidedFilesystemInfo& filesystem_info,
|
| + scoped_ptr<base::ListValue> response) {
|
| +
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| + PluginService *fs_service = PluginService::Get(
|
| + ProfileManager::GetActiveUserProfile());
|
| + DCHECK(fs_service);
|
| +
|
| + ProvidedFileSystemAdapter* fs_backend =
|
| + fs_service->GetProvidedFileSystemAdapter(
|
| + filesystem_info.plugin_name,
|
| + filesystem_info.filesystem_id);
|
| + if(fs_backend==nullptr)
|
| + return PP_ERROR_FAILED;
|
| + fs_backend->PushErrorResponse(response.Pass());
|
| + return PP_OK;
|
| +}
|
| +
|
| +bool PepperFilesystemProviderBackendChromeOS::FlushRequest(
|
| + scoped_ptr<base::ListValue> request) {
|
| + if(!request.get())
|
| + return false;
|
| +
|
| + if(!AddFromMessageToSharedMemory(*request))
|
| + return false;
|
| +
|
| + host_->SendUnsolicitedReply(
|
| + resource_,
|
| + PpapiPluginMsg_FilesystemProvider_OperationRequest(
|
| + PP_OperationType_WRITEFILE,
|
| + *request));
|
| + return true;
|
| +}
|
| +bool PepperFilesystemProviderBackendChromeOS::InitializeMemoryBuffer() {
|
| + // Already initialized
|
| + if(read_write_buffer_.get())
|
| + return true;
|
| + scoped_ptr<base::SharedMemory> buffer( new base::SharedMemory );
|
| + size_t size = kReaderBufferSize + kWriterBufferSize;
|
| + if (!buffer.get() ||
|
| + !buffer->CreateAndMapAnonymous(size))
|
| + return false;
|
| + read_write_buffer_=make_scoped_ptr(new ShmBuffer(size, buffer.Pass()));
|
| + if(!read_write_buffer_.get())
|
| + return false;
|
| + using ppapi::proxy::SerializedHandle;
|
| + std::vector<SerializedHandle> handles;
|
| + handles.push_back(
|
| + SerializedHandle(read_write_buffer_->shm->handle(), size ));
|
| + // Send a message to the plugin with the shared mem handle
|
| + host_->SendUnsolicitedReplyWithHandles(
|
| + resource_,
|
| + PpapiPluginMsg_FilesystemProvider_Buffers(
|
| + kReaderBufferSize,
|
| + kWriterBufferSize),
|
| + handles
|
| + );
|
| + return true;
|
| +}
|
| +bool PepperFilesystemProviderBackendChromeOS::AddFromSharedMemoryToMessage(
|
| + base::ListValue& message) {
|
| + DCHECK(read_write_buffer_.get());
|
| + double out = 0;
|
| + if(!message.GetDouble(2,&out))
|
| + return false;
|
| + size_t out_size = out;
|
| + if(out_size>kReaderBufferSize)
|
| + return false;
|
| +
|
| + // Replace the size with the actual data
|
| + bool status = message.Set(2, base::BinaryValue::CreateWithCopiedBuffer(
|
| + (const char*)read_write_buffer_->shm->memory(), out_size));
|
| + SendReadAck();
|
| + return status;
|
| +}
|
| +bool PepperFilesystemProviderBackendChromeOS::AddFromMessageToSharedMemory(
|
| + base::ListValue& message) {
|
| + if( !read_write_buffer_.get() )
|
| + return false;
|
| +
|
| + base::Value *dict_value = nullptr;
|
| + if(!message.Get(0,&dict_value))
|
| + return false;
|
| +
|
| + base::DictionaryValue* dict =
|
| + static_cast<base::DictionaryValue*>(dict_value);
|
| + const base::BinaryValue* binary_value = NULL;
|
| + if (!dict->GetBinary("data", &binary_value))
|
| + return false;
|
| + // This can be '0'
|
| + size_t binary_size =binary_value->GetSize();
|
| + // Skip the read buffer and copy to shared mem the buffer into
|
| + // the write portion of the buffer
|
| + if(binary_size>kWriterBufferSize)
|
| + return false;
|
| + memcpy( (char*)read_write_buffer_->shm->memory()+kReaderBufferSize,
|
| + binary_value->GetBuffer(),
|
| + binary_size);
|
| + dict->Remove( "data", nullptr );
|
| + dict->SetDouble( "size",binary_size);
|
| + return true;
|
| +}
|
| +bool PepperFilesystemProviderBackendChromeOS::PreprocessMessage(
|
| + base::ListValue& message,
|
| + bool& message_status,
|
| + int& operation_type) {
|
| + // Remove the custom "header" from the response
|
| + scoped_ptr<base::Value> operation_value = nullptr;
|
| + if (!message.Remove(0,&operation_value))
|
| + return false;
|
| + if (!operation_value->GetAsInteger(&operation_type))
|
| + return false;
|
| + // Get the status of the operation
|
| + scoped_ptr<base::Value> status_value=nullptr;
|
| + if (!message.Remove(0,&status_value))
|
| + return false;
|
| + if (!status_value->GetAsBoolean(&message_status))
|
| + return false;
|
| + switch (operation_type) {
|
| + case PP_OperationType_READFILE:
|
| + if (!AddFromSharedMemoryToMessage(message))
|
| + return false;
|
| + break;
|
| + case PP_OperationType_UNMOUNT:
|
| + if ( message_status )
|
| + mounted_ = false;
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void PepperFilesystemProviderBackendChromeOS::SendReadAck() {
|
| + // ACK the receipt and let the plugin know that if it has more
|
| + // requests it can send them
|
| + if (host_)
|
| + host_->SendUnsolicitedReply(resource_,
|
| + PpapiPluginMsg_FilesystemProvider_ReadAck());
|
| +}
|
| +
|
| +namespace filesystem_provider_internal {
|
| +scoped_ptr<MountOperationTranslator>
|
| + MountOperationTranslator::PopulateFromResponse(
|
| + const base::ListValue& request) {
|
| + const base::Value *dict_value = nullptr;
|
| + if(!request.Get(0,&dict_value))
|
| + return scoped_ptr<MountOperationTranslator>();
|
| +
|
| + const base::DictionaryValue* dict =
|
| + static_cast<const base::DictionaryValue*>(dict_value);
|
| +
|
| + scoped_ptr< MountOperationTranslator > out(new MountOperationTranslator);
|
| +
|
| + const base::Value* data_value = nullptr;
|
| + if (!dict->GetWithoutPathExpansion("fileSystemId", &data_value) ||
|
| + !data_value->IsType(base::Value::TYPE_STRING))
|
| + return scoped_ptr<MountOperationTranslator>();
|
| + if (!data_value->GetAsString(&out->file_system_id))
|
| + return scoped_ptr<MountOperationTranslator>();
|
| + if (!dict->GetWithoutPathExpansion("displayName", &data_value) ||
|
| + !data_value->IsType(base::Value::TYPE_STRING))
|
| + return scoped_ptr<MountOperationTranslator>();
|
| + if (!data_value->GetAsString(&out->display_name))
|
| + return scoped_ptr<MountOperationTranslator>();
|
| + if (!dict->GetWithoutPathExpansion("writable", &data_value) ||
|
| + !data_value->IsType(base::Value::TYPE_BOOLEAN))
|
| + return scoped_ptr<MountOperationTranslator>();
|
| + if (!data_value->GetAsBoolean(&out->writable))
|
| + return scoped_ptr<MountOperationTranslator>();
|
| +
|
| + if (!dict->GetWithoutPathExpansion("openedFilesLimit", &data_value) ||
|
| + !data_value->IsType(base::Value::TYPE_INTEGER))
|
| + return scoped_ptr<MountOperationTranslator>();
|
| + if (!data_value->GetAsInteger(&out->opened_files_limit))
|
| + return scoped_ptr<MountOperationTranslator>();
|
| +
|
| + return out.Pass();
|
| +}
|
| +} // namespace filesystem_provider_internal
|
| +} // namespace content
|
| +
|
|
|