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..28a5f7e9ef43537c4effe3f864ab06350fdc09a7 |
--- /dev/null |
+++ b/content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.cc |
@@ -0,0 +1,858 @@ |
+// 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/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 extensions::api::file_system_provider::ProviderError; |
+using chromeos::file_system_provider::ProvidedFileSystemInterface; |
+using chromeos::file_system_provider::Service; |
+using chromeos::file_system_provider::Source_Type; |
+using chromeos::PluginEventRouter; |
+using content::BrowserThread; |
+using ppapi::host::HostMessageContext; |
+ |
+#define MAKE_EVENT_ENTRY(x,handler,operation)\ |
+ std::pair<std::string,\ |
+ std::pair<DispatchEventImplCallback,PP_OperationType_Dev>>(\ |
+ extensions::api::file_system_provider::x::kEventName,\ |
+ std::pair<DispatchEventImplCallback,PP_OperationType_Dev>(\ |
+ base::Bind( &PepperFilesystemProviderBackendChromeOS::handler,\ |
+ weak_factory_.GetWeakPtr() ), operation ) ) |
+ |
+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; |
+ |
+base::File::Error PP_ProviderErrorToFileError( |
+ ProviderError error) { |
+ switch (error) { |
+ case ProviderError::PROVIDER_ERROR_OK: |
+ return base::File::FILE_OK; |
+ case ProviderError::PROVIDER_ERROR_FAILED: |
+ return base::File::FILE_ERROR_FAILED; |
+ case ProviderError::PROVIDER_ERROR_IN_USE: |
+ return base::File::FILE_ERROR_IN_USE; |
+ case ProviderError::PROVIDER_ERROR_EXISTS: |
+ return base::File::FILE_ERROR_EXISTS; |
+ case ProviderError::PROVIDER_ERROR_NOT_FOUND: |
+ return base::File::FILE_ERROR_NOT_FOUND; |
+ case ProviderError::PROVIDER_ERROR_ACCESS_DENIED: |
+ return base::File::FILE_ERROR_ACCESS_DENIED; |
+ case ProviderError::PROVIDER_ERROR_TOO_MANY_OPENED: |
+ return base::File::FILE_ERROR_TOO_MANY_OPENED; |
+ case ProviderError::PROVIDER_ERROR_NO_MEMORY: |
+ return base::File::FILE_ERROR_NO_MEMORY; |
+ case ProviderError::PROVIDER_ERROR_NO_SPACE: |
+ return base::File::FILE_ERROR_NO_SPACE; |
+ case ProviderError::PROVIDER_ERROR_NOT_A_DIRECTORY: |
+ return base::File::FILE_ERROR_NOT_A_DIRECTORY; |
+ case ProviderError::PROVIDER_ERROR_INVALID_OPERATION: |
+ return base::File::FILE_ERROR_INVALID_OPERATION; |
+ case ProviderError::PROVIDER_ERROR_SECURITY: |
+ return base::File::FILE_ERROR_SECURITY; |
+ case ProviderError::PROVIDER_ERROR_ABORT: |
+ return base::File::FILE_ERROR_ABORT; |
+ case ProviderError::PROVIDER_ERROR_NOT_A_FILE: |
+ return base::File::FILE_ERROR_NOT_A_FILE; |
+ case ProviderError::PROVIDER_ERROR_NOT_EMPTY: |
+ return base::File::FILE_ERROR_NOT_EMPTY; |
+ case ProviderError::PROVIDER_ERROR_INVALID_URL: |
+ return base::File::FILE_ERROR_INVALID_URL; |
+ case ProviderError::PROVIDER_ERROR_IO: |
+ return base::File::FILE_ERROR_IO; |
+ case ProviderError::PROVIDER_ERROR_NONE: |
+ NOTREACHED(); |
+ } |
+ |
+ return base::File::FILE_ERROR_FAILED; |
+} |
+ |
+} // 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:: |
+ ShmChannelSynchronizer::ShmChannelSynchronizer( |
+ uint32_t size, FlushRequestCallback callback) |
+ : max_size(size), |
+ ready(true), |
+ callback(callback){ |
+} |
+PepperFilesystemProviderBackendChromeOS:: |
+ ShmChannelSynchronizer::~ShmChannelSynchronizer() { |
+} |
+ |
+bool PepperFilesystemProviderBackendChromeOS:: |
+ ShmChannelSynchronizer::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:: |
+ ShmChannelSynchronizer::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:: |
+ ShmChannelSynchronizer::AckLastPushedRequest() { |
+ return ready = true; |
+} |
+ |
+uint32_t PepperFilesystemProviderBackendChromeOS:: |
+ ShmChannelSynchronizer::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 ShmChannelSynchronizer( |
+ kMaximumCachedReplies, |
+ base::Bind( |
+ &PepperFilesystemProviderBackendChromeOS:: |
+ FlushRequest, |
+ base::Unretained(this)))), |
+ weak_factory_(this) { |
+ |
+ filesystem_info_.plugin_name = std::string("Plugin_") + |
+ std::to_string(instance); |
+ |
+ std::pair< |
+ std::string, std::pair<DispatchEventImplCallback,PP_OperationType_Dev> > |
+ ev[] ={ |
+ MAKE_EVENT_ENTRY( |
+ OnAbortRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_ABORT), |
+ MAKE_EVENT_ENTRY( |
+ OnCloseFileRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_CLOSEFILE), |
+ MAKE_EVENT_ENTRY( |
+ OnCopyEntryRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_COPYENTRY), |
+ MAKE_EVENT_ENTRY( |
+ OnCreateDirectoryRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_CREATEDIRECTORY), |
+ MAKE_EVENT_ENTRY( |
+ OnCreateFileRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_CREATEFILE), |
+ MAKE_EVENT_ENTRY( |
+ OnDeleteEntryRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_DELETEENTRY), |
+ MAKE_EVENT_ENTRY( |
+ OnGetMetadataRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_GETMETADATA), |
+ MAKE_EVENT_ENTRY( |
+ OnMoveEntryRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_MOVEENTRY), |
+ MAKE_EVENT_ENTRY( |
+ OnOpenFileRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_OPENFILE), |
+ MAKE_EVENT_ENTRY( |
+ OnReadDirectoryRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_READDIRECTORY), |
+ MAKE_EVENT_ENTRY( |
+ OnReadFileRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_READFILE), |
+ MAKE_EVENT_ENTRY( |
+ OnTruncateRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_TRUNCATEENTRY), |
+ MAKE_EVENT_ENTRY( |
+ OnUnmountRequested, |
+ SendOperationRequestToPlugin, |
+ PP_OperationType_UNMOUNT), |
+ MAKE_EVENT_ENTRY( |
+ OnWriteFileRequested, |
+ SendWriteRequestToPlugin, |
+ PP_OperationType_WRITEFILE) |
+ }; |
+ |
+ for ( size_t i = 0; i < sizeof( ev ) / sizeof( ev[0] ); ++i ) { |
+ handlers_list_.insert( ev[i] ); |
+ events_.push_back( ev[i].first ); |
+ } |
+} |
+ |
+PepperFilesystemProviderBackendChromeOS:: |
+~PepperFilesystemProviderBackendChromeOS() { |
+ // Unregister the filesystem if state indicates |
+ // that we have a mounted filesystem |
+ if (mounted_) { |
+ // Unregister any registered event from the PluginEventRouter |
+ UnregisterFilesystemEventListeners(); |
+ // 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) { |
+ |
+ 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 wanted filesystem configuration |
+ ProvidedFilesystemInfo filesystem_info; |
+ filesystem_info.plugin_name = filesystem_info_.plugin_name; |
+ filesystem_info.filesystem_id = mount_info->file_system_id; |
+ filesystem_info.display_name = mount_info->display_name; |
+ filesystem_info.writable = mount_info->writable; |
+ 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, std::string fsid) { |
+ |
+ if(!mounted_) { |
+ UnmountReplyOnIO( |
+ context->MakeReplyMessageContext(), |
+ base::File::FILE_ERROR_NOT_FOUND); |
+ } |
+ |
+ // Remove registered events from PluginEventRouter |
+ UnregisterFilesystemEventListeners(); |
+ |
+ 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()) |
+ return PP_ERROR_FAILED; |
+ // Remove the custom "header" from the response |
+ scoped_ptr<base::Value> operation_value = nullptr; |
+ int operation_type = PP_OperationType_NONE; |
+ if (!response->Remove(0,&operation_value)) |
+ return PP_ERROR_FAILED; |
+ if (!operation_value->GetAsInteger(&operation_type)) |
+ return PP_ERROR_FAILED; |
+ // Get the status of the operation |
+ scoped_ptr<base::Value> status_value=nullptr; |
+ bool status = false; |
+ if (!response->Remove(0,&status_value)) |
+ return PP_ERROR_FAILED; |
+ if (!status_value->GetAsBoolean(&status)) |
+ return PP_ERROR_FAILED; |
+ |
+ if ( status ) {// success |
+ |
+ if (operation_type==PP_OperationType_READFILE) { // a preprocess stage |
+ AddFromSharedMemoryToMessage(*response); |
+ // ACK the receipt and let the plugin know that if it has more |
+ // requests it can send them |
+ host_->SendUnsolicitedReply( |
+ resource_, |
+ PpapiPluginMsg_FilesystemProvider_ReadAck() |
+ ); |
+ } |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind( |
+ base::IgnoreResult( |
+ &PepperFilesystemProviderBackendChromeOS:: |
+ OnGeneralSuccessResponse), |
+ operation_type, |
+ filesystem_info_, |
+ base::Passed(response.Pass())) |
+ ); |
+ } else { // failure |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind( |
+ base::IgnoreResult( |
+ &PepperFilesystemProviderBackendChromeOS:: |
+ OnGeneralErrorResponse), |
+ 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; |
+} |
+ |
+// Add all events to the PluginEventRouter list of dispatchable events |
+void PepperFilesystemProviderBackendChromeOS:: |
+RegisterFilesystemEventListeners() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ PluginEventRouter *router = PluginEventRouter::GetInstance(); |
+ if (router!=nullptr) |
+ router->AddEventsListener( events_, this, filesystem_info_.plugin_name ); |
+} |
+// Remove all events from the PluginEventRouter list of dispatchable events |
+void PepperFilesystemProviderBackendChromeOS:: |
+UnregisterFilesystemEventListeners() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ PluginEventRouter *router = PluginEventRouter::GetInstance(); |
+ if (router!=nullptr) |
+ router->RemoveEventsListeners( events_, this, 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); |
+ |
+ Service *fs_service = Service::Get(ProfileManager::GetActiveUserProfile()); |
+ DCHECK(fs_service); |
+ |
+ chromeos::file_system_provider::MountOptions options( |
+ filesystem_info.filesystem_id, filesystem_info.display_name); |
+ |
+ options.writable = filesystem_info.writable; |
+ options.opened_files_limit = filesystem_info.opened_files_limit; |
+ options.supports_notify_tag = false; // Check this |
+ |
+ base::File::Error error = fs_service->MountFileSystem( |
+ filesystem_info.plugin_name, |
+ options, |
+ Source_Type::plugin ); |
+ |
+ 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); |
+ |
+ // Do not register and send error back |
+ if ( err != base::File::FILE_OK ) { |
+ reply_msg.params.set_result(PP_OK); |
+ host_->SendReply( |
+ reply_msg, |
+ PpapiPluginMsg_FilesystemProvider_MountReply( PP_ProviderError_FAILED ) |
+ ); |
+ return; |
+ } |
+ |
+ filesystem_info_.writable = filesystem_info.writable; |
+ filesystem_info_.opened_files_limit = filesystem_info.opened_files_limit; |
+ filesystem_info_.filesystem_id = filesystem_info.filesystem_id; |
+ filesystem_info_.display_name = filesystem_info.display_name; |
+ mounted_ = true; |
+ |
+ // Initialize the shared memory buffers if needed |
+ if (!read_write_buffer_.get()) |
+ InitializeMemoryBuffer(); |
+ RegisterFilesystemEventListeners(); |
+ |
+ reply_msg.params.set_result(PP_OK); |
+ host_->SendReply( |
+ reply_msg, |
+ PpapiPluginMsg_FilesystemProvider_MountReply( PP_ProviderError_OK ) |
+ ); |
+} |
+ |
+//static |
+// Responsible with removal of the filesystem backend |
+base::File::Error PepperFilesystemProviderBackendChromeOS:: |
+UnregisterFilesystemOnUI( |
+ ProvidedFilesystemInfo filesystem_info) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ Service *fs_service = Service::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::Service::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 |
+ UnregisterFilesystemEventListeners(); |
+ |
+ mounted_ = false; |
+ filesystem_info_.writable = false; |
+ filesystem_info_.opened_files_limit = 0; |
+ filesystem_info_.filesystem_id = ""; |
+ filesystem_info_.display_name = ""; |
+ |
+ // Send result to the plugin |
+ host_->SendReply( |
+ reply_msg, |
+ PpapiPluginMsg_FilesystemProvider_MountReply( PP_ProviderError_OK ) |
+ ); |
+} |
+ |
+// Handle events that are dispatched by the PluginEventRouter |
+void PepperFilesystemProviderBackendChromeOS::OnDispatchEvent( |
+ std::string event_name, scoped_ptr<base::ListValue> event_args) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ |
+ ListOfHandlersIterator it = handlers_list_.find( event_name ); |
+ if ( it != handlers_list_.end() ) |
+ it->second.first.Run( it->second.second, event_args.Pass() ); |
+} |
+ |
+// Sends requests to plugin |
+void PepperFilesystemProviderBackendChromeOS::SendOperationRequestToPlugin( |
+ PP_OperationType_Dev operation_type, |
+ scoped_ptr<base::ListValue> event_args) { |
+ |
+ //TODO(sabin): Remove this when done testing |
+ if(operation_type==PP_OperationType_OPENFILE) |
+ time_stamp_=std::chrono::system_clock::now(); |
+ else if(operation_type==PP_OperationType_CLOSEFILE) { |
+ 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( |
+ operation_type, |
+ *event_args) |
+ ); |
+ |
+} |
+ |
+void PepperFilesystemProviderBackendChromeOS::SendWriteRequestToPlugin( |
+ PP_OperationType_Dev operation_type, |
+ scoped_ptr<base::ListValue> request) { |
+ // 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()); |
+} |
+ |
+// Transforms messages that are received from |
+// the plugin in response of filesystem operations and sends |
+// them back to the filesystem backend. |
+int32_t PepperFilesystemProviderBackendChromeOS::OnGeneralSuccessResponse( |
+ int operation, |
+ ProvidedFilesystemInfo filesystem_info, |
+ scoped_ptr<base::ListValue> args) { |
+ |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ Service *fs_service = Service::Get(ProfileManager::GetActiveUserProfile()); |
+ DCHECK(fs_service); |
+ |
+ ProvidedFileSystemInterface* fs_interface = |
+ fs_service->GetProvidedFileSystem( |
+ filesystem_info.plugin_name, |
+ filesystem_info.filesystem_id); |
+ |
+ if (fs_interface==nullptr) |
+ return PP_ERROR_FAILED; |
+ |
+ switch(operation) { |
+ case PP_OperationType_READDIRECTORY: { |
+ using extensions::api:: |
+ file_system_provider_internal::ReadDirectoryRequestedSuccess:: |
+ Params; |
+ scoped_ptr<Params> params(Params::Create(*args)); |
+ if(!params.get()) |
+ return PP_ERROR_FAILED; |
+ |
+ const bool has_more = params->has_more; |
+ if ( base::File::FILE_OK!= |
+ fs_interface->GetRequestManager()->FulfillRequest( |
+ params->request_id, |
+ chromeos::file_system_provider::RequestValue:: |
+ CreateForReadDirectorySuccess(params.Pass()), |
+ has_more) |
+ ) |
+ return PP_ERROR_FAILED; |
+ } |
+ break; |
+ case PP_OperationType_GETMETADATA: { |
+ using extensions::api::file_system_provider_internal:: |
+ GetMetadataRequestedSuccess::Params; |
+ scoped_ptr<Params> params(Params::Create(*args)); |
+ if(!params.get()) |
+ return PP_ERROR_FAILED; |
+ |
+ if (base::File::FILE_OK!= |
+ fs_interface->GetRequestManager()->FulfillRequest( |
+ params->request_id, |
+ chromeos::file_system_provider::RequestValue:: |
+ CreateForGetMetadataSuccess(params.Pass()), |
+ false) |
+ ) |
+ return PP_ERROR_FAILED; |
+ } |
+ break; |
+ case PP_OperationType_READFILE: { |
+ using extensions::api::file_system_provider_internal:: |
+ ReadFileRequestedSuccess::Params; |
+ scoped_ptr<Params> params(Params::Create(*args)); |
+ if (!params.get()) |
+ return PP_ERROR_FAILED; |
+ |
+ const bool has_more = params->has_more; |
+ if (base::File::FILE_OK!= |
+ fs_interface->GetRequestManager()->FulfillRequest( |
+ params->request_id, |
+ chromeos::file_system_provider::RequestValue:: |
+ CreateForReadFileSuccess(params.Pass()), |
+ has_more) ) |
+ return PP_ERROR_FAILED; |
+ } |
+ break; |
+ case PP_OperationType_UNMOUNT: { |
+ using extensions::api::file_system_provider_internal:: |
+ UnmountRequestedSuccess::Params; |
+ scoped_ptr<Params> params(Params::Create(*args)); |
+ if(!params.get()) |
+ return PP_ERROR_FAILED; |
+ |
+ if (base::File::FILE_OK!= |
+ fs_service->UnmountFileSystem( |
+ filesystem_info.plugin_name, filesystem_info.filesystem_id, |
+ chromeos::file_system_provider::Service::UNMOUNT_REASON_USER) |
+ ) |
+ return PP_ERROR_FAILED; |
+ } |
+ break; |
+ default: { |
+ using extensions::api::file_system_provider_internal:: |
+ OperationRequestedSuccess::Params; |
+ scoped_ptr<Params> params(Params::Create(*args)); |
+ if(!params.get()) |
+ return PP_ERROR_FAILED; |
+ |
+ if (base::File::FILE_OK!= |
+ fs_interface->GetRequestManager()->FulfillRequest( |
+ params->request_id, |
+ chromeos::file_system_provider::RequestValue:: |
+ CreateForOperationSuccess(params.Pass()), |
+ false) |
+ ) |
+ return PP_ERROR_FAILED; |
+ } |
+ break; |
+ } |
+ return PP_OK; |
+} |
+ |
+int32_t PepperFilesystemProviderBackendChromeOS::OnGeneralErrorResponse( |
+ ProvidedFilesystemInfo filesystem_info, |
+ scoped_ptr<base::ListValue> args) { |
+ |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ Service *fs_service = Service::Get(ProfileManager::GetActiveUserProfile()); |
+ DCHECK(fs_service); |
+ |
+ ProvidedFileSystemInterface* fs_interface = |
+ fs_service->GetProvidedFileSystem( |
+ filesystem_info.plugin_name, |
+ filesystem_info.filesystem_id); |
+ if(fs_interface==nullptr) |
+ return PP_ERROR_FAILED; |
+ |
+ using extensions::api::file_system_provider_internal:: |
+ OperationRequestedError::Params; |
+ scoped_ptr<Params> params(Params::Create(*args)); |
+ if(!params.get()) |
+ return PP_ERROR_FAILED; |
+ |
+ const base::File::Error error = PP_ProviderErrorToFileError(params->error); |
+ |
+ if( base::File::FILE_OK!= |
+ fs_interface->GetRequestManager()->RejectRequest( |
+ params->request_id, |
+ chromeos::file_system_provider::RequestValue:: |
+ CreateForOperationError(params.Pass()), |
+ error) |
+ ) |
+ return PP_ERROR_FAILED; |
+ 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 false; |
+ 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 |
+ return message.Set(2, base::BinaryValue::CreateWithCopiedBuffer( |
+ (const char*)read_write_buffer_->shm->memory(), out_size)); |
+} |
+ |
+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; |
+} |
+ |
+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 content |
+ |