OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/browser/renderer_host/pepper/pepper_filesystem_provider_backen
d_chromeos.h" |
| 6 |
| 7 #include <chrono> |
| 8 |
| 9 #include "base/memory/shared_memory.h" |
| 10 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info
.h" |
| 11 #include "chrome/browser/chromeos/file_system_provider/request_manager.h" |
| 12 #include "chrome/browser/chromeos/file_system_provider/service.h" |
| 13 #include "chrome/browser/profiles/profile_manager.h" |
| 14 #include "content/public/browser/browser_ppapi_host.h" |
| 15 #include "content/public/browser/browser_thread.h" |
| 16 #include "ppapi/c/pp_errors.h" |
| 17 #include "ppapi/host/ppapi_host.h" |
| 18 #include "ppapi/proxy/ppapi_messages.h" |
| 19 |
| 20 using extensions::api::file_system_provider::ProviderError; |
| 21 using chromeos::file_system_provider::ProvidedFileSystemInterface; |
| 22 using chromeos::file_system_provider::Service; |
| 23 using chromeos::file_system_provider::Source_Type; |
| 24 using chromeos::PluginEventRouter; |
| 25 using content::BrowserThread; |
| 26 using ppapi::host::HostMessageContext; |
| 27 |
| 28 #define MAKE_EVENT_ENTRY(x,handler,operation)\ |
| 29 std::pair<std::string,\ |
| 30 std::pair<DispatchEventImplCallback,PP_OperationType_Dev>>(\ |
| 31 extensions::api::file_system_provider::x::kEventName,\ |
| 32 std::pair<DispatchEventImplCallback,PP_OperationType_Dev>(\ |
| 33 base::Bind( &PepperFilesystemProviderBackendChromeOS::handler,\ |
| 34 weak_factory_.GetWeakPtr() ), operation ) ) |
| 35 |
| 36 namespace content { |
| 37 |
| 38 namespace { |
| 39 |
| 40 // TODO(sabin): find a way to get the size of the stream reader internal |
| 41 // buffer from the backend |
| 42 // Size of the stream reader internal buffer. At most this number of bytes will |
| 43 // be read ahead of the requested data. |
| 44 const uint32_t kReaderBufferSize = 512 * 1024; // 512KB. |
| 45 |
| 46 // Size of the stream writer internal buffer. At most this number of bytes will |
| 47 // be postponed for writing. |
| 48 const uint32_t kWriterBufferSize = 512 * 1024; // 512KB. |
| 49 |
| 50 // The number of requests that can be buffered |
| 51 const uint32_t kMaximumCachedReplies = 10; |
| 52 |
| 53 base::File::Error PP_ProviderErrorToFileError( |
| 54 ProviderError error) { |
| 55 switch (error) { |
| 56 case ProviderError::PROVIDER_ERROR_OK: |
| 57 return base::File::FILE_OK; |
| 58 case ProviderError::PROVIDER_ERROR_FAILED: |
| 59 return base::File::FILE_ERROR_FAILED; |
| 60 case ProviderError::PROVIDER_ERROR_IN_USE: |
| 61 return base::File::FILE_ERROR_IN_USE; |
| 62 case ProviderError::PROVIDER_ERROR_EXISTS: |
| 63 return base::File::FILE_ERROR_EXISTS; |
| 64 case ProviderError::PROVIDER_ERROR_NOT_FOUND: |
| 65 return base::File::FILE_ERROR_NOT_FOUND; |
| 66 case ProviderError::PROVIDER_ERROR_ACCESS_DENIED: |
| 67 return base::File::FILE_ERROR_ACCESS_DENIED; |
| 68 case ProviderError::PROVIDER_ERROR_TOO_MANY_OPENED: |
| 69 return base::File::FILE_ERROR_TOO_MANY_OPENED; |
| 70 case ProviderError::PROVIDER_ERROR_NO_MEMORY: |
| 71 return base::File::FILE_ERROR_NO_MEMORY; |
| 72 case ProviderError::PROVIDER_ERROR_NO_SPACE: |
| 73 return base::File::FILE_ERROR_NO_SPACE; |
| 74 case ProviderError::PROVIDER_ERROR_NOT_A_DIRECTORY: |
| 75 return base::File::FILE_ERROR_NOT_A_DIRECTORY; |
| 76 case ProviderError::PROVIDER_ERROR_INVALID_OPERATION: |
| 77 return base::File::FILE_ERROR_INVALID_OPERATION; |
| 78 case ProviderError::PROVIDER_ERROR_SECURITY: |
| 79 return base::File::FILE_ERROR_SECURITY; |
| 80 case ProviderError::PROVIDER_ERROR_ABORT: |
| 81 return base::File::FILE_ERROR_ABORT; |
| 82 case ProviderError::PROVIDER_ERROR_NOT_A_FILE: |
| 83 return base::File::FILE_ERROR_NOT_A_FILE; |
| 84 case ProviderError::PROVIDER_ERROR_NOT_EMPTY: |
| 85 return base::File::FILE_ERROR_NOT_EMPTY; |
| 86 case ProviderError::PROVIDER_ERROR_INVALID_URL: |
| 87 return base::File::FILE_ERROR_INVALID_URL; |
| 88 case ProviderError::PROVIDER_ERROR_IO: |
| 89 return base::File::FILE_ERROR_IO; |
| 90 case ProviderError::PROVIDER_ERROR_NONE: |
| 91 NOTREACHED(); |
| 92 } |
| 93 |
| 94 return base::File::FILE_ERROR_FAILED; |
| 95 } |
| 96 |
| 97 } // namespace |
| 98 |
| 99 PepperFilesystemProviderBackendChromeOS:: |
| 100 ProvidedFilesystemInfo::ProvidedFilesystemInfo() |
| 101 :filesystem_id("none"), |
| 102 display_name("none"), |
| 103 plugin_name("none"), |
| 104 writable(false), |
| 105 opened_files_limit(0) { |
| 106 } |
| 107 PepperFilesystemProviderBackendChromeOS::ShmBuffer::ShmBuffer( |
| 108 uint32_t size, scoped_ptr<base::SharedMemory> shm) |
| 109 : size(size),shm(shm.Pass()) { |
| 110 DCHECK(this->shm); |
| 111 } |
| 112 |
| 113 PepperFilesystemProviderBackendChromeOS::ShmBuffer::~ShmBuffer() { |
| 114 |
| 115 } |
| 116 |
| 117 PepperFilesystemProviderBackendChromeOS:: |
| 118 ShmChannelSynchronizer::ShmChannelSynchronizer( |
| 119 uint32_t size, FlushRequestCallback callback) |
| 120 : max_size(size), |
| 121 ready(true), |
| 122 callback(callback){ |
| 123 } |
| 124 PepperFilesystemProviderBackendChromeOS:: |
| 125 ShmChannelSynchronizer::~ShmChannelSynchronizer() { |
| 126 } |
| 127 |
| 128 bool PepperFilesystemProviderBackendChromeOS:: |
| 129 ShmChannelSynchronizer::EnqueueRequest( |
| 130 scoped_ptr<base::ListValue> response) { |
| 131 // If channel ready send it straight away |
| 132 if(ready) { |
| 133 ready = !callback.Run(response.Pass()); |
| 134 if(!ready) |
| 135 return true; |
| 136 } |
| 137 // If channel is not ready or failed to send |
| 138 // cache the request |
| 139 if(size() + 1 > max_size) |
| 140 return false; |
| 141 replies.push_back( response.Pass() ); |
| 142 return true; |
| 143 } |
| 144 |
| 145 bool PepperFilesystemProviderBackendChromeOS:: |
| 146 ShmChannelSynchronizer::PushNextRequest() { |
| 147 // Try and send the request |
| 148 scoped_ptr<base::ListValue> response; |
| 149 while (size()>0 && ready ) { |
| 150 response.reset(replies.front()); |
| 151 replies.weak_erase(replies.begin()); |
| 152 ready = !callback.Run(response.Pass()); |
| 153 } |
| 154 return !ready; |
| 155 } |
| 156 |
| 157 bool |
| 158 PepperFilesystemProviderBackendChromeOS:: |
| 159 ShmChannelSynchronizer::AckLastPushedRequest() { |
| 160 return ready = true; |
| 161 } |
| 162 |
| 163 uint32_t PepperFilesystemProviderBackendChromeOS:: |
| 164 ShmChannelSynchronizer::size() { |
| 165 return replies.size(); |
| 166 } |
| 167 |
| 168 |
| 169 |
| 170 PepperFilesystemProviderBackendChromeOS:: |
| 171 PepperFilesystemProviderBackendChromeOS( |
| 172 content::BrowserPpapiHost *host, |
| 173 PP_Instance instance, |
| 174 PP_Resource resource) |
| 175 : mounted_(false), |
| 176 host_(host ? host->GetPpapiHost() : nullptr), |
| 177 resource_(resource), |
| 178 write_channel_controller_(new ShmChannelSynchronizer( |
| 179 kMaximumCachedReplies, |
| 180 base::Bind( |
| 181 &PepperFilesystemProviderBackendChromeOS:: |
| 182 FlushRequest, |
| 183 base::Unretained(this)))), |
| 184 weak_factory_(this) { |
| 185 |
| 186 filesystem_info_.plugin_name = std::string("Plugin_") + |
| 187 std::to_string(instance); |
| 188 |
| 189 std::pair< |
| 190 std::string, std::pair<DispatchEventImplCallback,PP_OperationType_Dev> > |
| 191 ev[] ={ |
| 192 MAKE_EVENT_ENTRY( |
| 193 OnAbortRequested, |
| 194 SendOperationRequestToPlugin, |
| 195 PP_OperationType_ABORT), |
| 196 MAKE_EVENT_ENTRY( |
| 197 OnCloseFileRequested, |
| 198 SendOperationRequestToPlugin, |
| 199 PP_OperationType_CLOSEFILE), |
| 200 MAKE_EVENT_ENTRY( |
| 201 OnCopyEntryRequested, |
| 202 SendOperationRequestToPlugin, |
| 203 PP_OperationType_COPYENTRY), |
| 204 MAKE_EVENT_ENTRY( |
| 205 OnCreateDirectoryRequested, |
| 206 SendOperationRequestToPlugin, |
| 207 PP_OperationType_CREATEDIRECTORY), |
| 208 MAKE_EVENT_ENTRY( |
| 209 OnCreateFileRequested, |
| 210 SendOperationRequestToPlugin, |
| 211 PP_OperationType_CREATEFILE), |
| 212 MAKE_EVENT_ENTRY( |
| 213 OnDeleteEntryRequested, |
| 214 SendOperationRequestToPlugin, |
| 215 PP_OperationType_DELETEENTRY), |
| 216 MAKE_EVENT_ENTRY( |
| 217 OnGetMetadataRequested, |
| 218 SendOperationRequestToPlugin, |
| 219 PP_OperationType_GETMETADATA), |
| 220 MAKE_EVENT_ENTRY( |
| 221 OnMoveEntryRequested, |
| 222 SendOperationRequestToPlugin, |
| 223 PP_OperationType_MOVEENTRY), |
| 224 MAKE_EVENT_ENTRY( |
| 225 OnOpenFileRequested, |
| 226 SendOperationRequestToPlugin, |
| 227 PP_OperationType_OPENFILE), |
| 228 MAKE_EVENT_ENTRY( |
| 229 OnReadDirectoryRequested, |
| 230 SendOperationRequestToPlugin, |
| 231 PP_OperationType_READDIRECTORY), |
| 232 MAKE_EVENT_ENTRY( |
| 233 OnReadFileRequested, |
| 234 SendOperationRequestToPlugin, |
| 235 PP_OperationType_READFILE), |
| 236 MAKE_EVENT_ENTRY( |
| 237 OnTruncateRequested, |
| 238 SendOperationRequestToPlugin, |
| 239 PP_OperationType_TRUNCATEENTRY), |
| 240 MAKE_EVENT_ENTRY( |
| 241 OnUnmountRequested, |
| 242 SendOperationRequestToPlugin, |
| 243 PP_OperationType_UNMOUNT), |
| 244 MAKE_EVENT_ENTRY( |
| 245 OnWriteFileRequested, |
| 246 SendWriteRequestToPlugin, |
| 247 PP_OperationType_WRITEFILE) |
| 248 }; |
| 249 |
| 250 for ( size_t i = 0; i < sizeof( ev ) / sizeof( ev[0] ); ++i ) { |
| 251 handlers_list_.insert( ev[i] ); |
| 252 events_.push_back( ev[i].first ); |
| 253 } |
| 254 } |
| 255 |
| 256 PepperFilesystemProviderBackendChromeOS:: |
| 257 ~PepperFilesystemProviderBackendChromeOS() { |
| 258 // Unregister the filesystem if state indicates |
| 259 // that we have a mounted filesystem |
| 260 if (mounted_) { |
| 261 // Unregister any registered event from the PluginEventRouter |
| 262 UnregisterFilesystemEventListeners(); |
| 263 // Unregister the filesystem backend on the |
| 264 // proper thread from Service |
| 265 BrowserThread::PostTask( |
| 266 BrowserThread::UI, |
| 267 FROM_HERE, |
| 268 base::Bind( |
| 269 base::IgnoreResult( |
| 270 &PepperFilesystemProviderBackendChromeOS:: |
| 271 UnregisterFilesystemOnUI), |
| 272 filesystem_info_ |
| 273 ) |
| 274 ); |
| 275 } |
| 276 } |
| 277 |
| 278 // Called when PpapiHostMsg_FilesystemProvider_Mount is received |
| 279 // Forwards request to RegisterFilesystemOnUI |
| 280 // Response is sent from MountReplyOnIO |
| 281 int32_t PepperFilesystemProviderBackendChromeOS::SendMountRequest( |
| 282 ppapi::host::HostMessageContext *context, |
| 283 const base::ListValue& request) { |
| 284 |
| 285 base::File::Error status = base::File::FILE_OK; |
| 286 if (mounted_) |
| 287 status = base::File::FILE_ERROR_EXISTS; |
| 288 |
| 289 scoped_ptr<MountOperationTranslator> mount_info = |
| 290 MountOperationTranslator::PopulateFromResponse(request); |
| 291 if ( !mount_info.get() ) |
| 292 status = base::File::FILE_ERROR_FAILED; |
| 293 |
| 294 // Stop and send failure back to the plugin |
| 295 if (status!=base::File::FILE_OK) { |
| 296 MountReplyOnIO( |
| 297 context->MakeReplyMessageContext(), |
| 298 filesystem_info_, base::File::FILE_ERROR_EXISTS); |
| 299 return PP_OK_COMPLETIONPENDING; |
| 300 } |
| 301 // Populate the wanted filesystem configuration |
| 302 ProvidedFilesystemInfo filesystem_info; |
| 303 filesystem_info.plugin_name = filesystem_info_.plugin_name; |
| 304 filesystem_info.filesystem_id = mount_info->file_system_id; |
| 305 filesystem_info.display_name = mount_info->display_name; |
| 306 filesystem_info.writable = mount_info->writable; |
| 307 filesystem_info.opened_files_limit = mount_info->opened_files_limit; |
| 308 // Change thread to create the filesystem backend on the |
| 309 // UI thread. The result of this action is to be interpreted |
| 310 // on the IO thread. |
| 311 BrowserThread::PostTaskAndReplyWithResult( |
| 312 BrowserThread::UI, |
| 313 FROM_HERE, |
| 314 base::Bind( |
| 315 // This creates a filesystem backend owned by the Service |
| 316 // entity |
| 317 &PepperFilesystemProviderBackendChromeOS::RegisterFilesystemOnUI, |
| 318 filesystem_info), |
| 319 // This is called after the above returns to interpret result |
| 320 base::Bind( |
| 321 &PepperFilesystemProviderBackendChromeOS::MountReplyOnIO, |
| 322 weak_factory_.GetWeakPtr(), |
| 323 context->MakeReplyMessageContext(), |
| 324 filesystem_info |
| 325 ) |
| 326 ); |
| 327 return PP_OK_COMPLETIONPENDING; |
| 328 } |
| 329 |
| 330 // Called when PpapiHostMsg_FilesystemProvider_Unmount is received |
| 331 // Forwards request to UnregisterFilesystemOnUI |
| 332 // Response is sent from MountReplyOnIO |
| 333 int32_t PepperFilesystemProviderBackendChromeOS::SendUnmountRequest( |
| 334 ppapi::host::HostMessageContext *context, std::string fsid) { |
| 335 |
| 336 if(!mounted_) { |
| 337 UnmountReplyOnIO( |
| 338 context->MakeReplyMessageContext(), |
| 339 base::File::FILE_ERROR_NOT_FOUND); |
| 340 } |
| 341 |
| 342 // Remove registered events from PluginEventRouter |
| 343 UnregisterFilesystemEventListeners(); |
| 344 |
| 345 BrowserThread::PostTaskAndReplyWithResult( |
| 346 BrowserThread::UI, |
| 347 FROM_HERE, |
| 348 base::Bind( |
| 349 &PepperFilesystemProviderBackendChromeOS::UnregisterFilesystemOnUI, |
| 350 filesystem_info_), |
| 351 base::Bind( &PepperFilesystemProviderBackendChromeOS::UnmountReplyOnIO, |
| 352 weak_factory_.GetWeakPtr(), |
| 353 context->MakeReplyMessageContext()) |
| 354 ); |
| 355 return PP_OK_COMPLETIONPENDING; |
| 356 } |
| 357 |
| 358 int32_t PepperFilesystemProviderBackendChromeOS::OnPluginResponse( |
| 359 ppapi::host::HostMessageContext* context, |
| 360 const base::ListValue& plugin_response) { |
| 361 scoped_ptr<base::ListValue> response( plugin_response.DeepCopy() ); |
| 362 if (!response.get()) |
| 363 return PP_ERROR_FAILED; |
| 364 // Remove the custom "header" from the response |
| 365 scoped_ptr<base::Value> operation_value = nullptr; |
| 366 int operation_type = PP_OperationType_NONE; |
| 367 if (!response->Remove(0,&operation_value)) |
| 368 return PP_ERROR_FAILED; |
| 369 if (!operation_value->GetAsInteger(&operation_type)) |
| 370 return PP_ERROR_FAILED; |
| 371 // Get the status of the operation |
| 372 scoped_ptr<base::Value> status_value=nullptr; |
| 373 bool status = false; |
| 374 if (!response->Remove(0,&status_value)) |
| 375 return PP_ERROR_FAILED; |
| 376 if (!status_value->GetAsBoolean(&status)) |
| 377 return PP_ERROR_FAILED; |
| 378 |
| 379 if ( status ) {// success |
| 380 |
| 381 if (operation_type==PP_OperationType_READFILE) { // a preprocess stage |
| 382 AddFromSharedMemoryToMessage(*response); |
| 383 // ACK the receipt and let the plugin know that if it has more |
| 384 // requests it can send them |
| 385 host_->SendUnsolicitedReply( |
| 386 resource_, |
| 387 PpapiPluginMsg_FilesystemProvider_ReadAck() |
| 388 ); |
| 389 } |
| 390 BrowserThread::PostTask( |
| 391 BrowserThread::UI, |
| 392 FROM_HERE, |
| 393 base::Bind( |
| 394 base::IgnoreResult( |
| 395 &PepperFilesystemProviderBackendChromeOS:: |
| 396 OnGeneralSuccessResponse), |
| 397 operation_type, |
| 398 filesystem_info_, |
| 399 base::Passed(response.Pass())) |
| 400 ); |
| 401 } else { // failure |
| 402 BrowserThread::PostTask( |
| 403 BrowserThread::UI, |
| 404 FROM_HERE, |
| 405 base::Bind( |
| 406 base::IgnoreResult( |
| 407 &PepperFilesystemProviderBackendChromeOS:: |
| 408 OnGeneralErrorResponse), |
| 409 filesystem_info_, |
| 410 base::Passed(response.Pass())) |
| 411 ); |
| 412 } |
| 413 |
| 414 return PP_OK; |
| 415 } |
| 416 |
| 417 // Sends next cached request if there is any pending |
| 418 int32_t PepperFilesystemProviderBackendChromeOS::OnPluginWriteAck( |
| 419 ppapi::host::HostMessageContext* ) { |
| 420 write_channel_controller_->AckLastPushedRequest(); |
| 421 write_channel_controller_->PushNextRequest(); |
| 422 return PP_OK; |
| 423 } |
| 424 |
| 425 // Add all events to the PluginEventRouter list of dispatchable events |
| 426 void PepperFilesystemProviderBackendChromeOS:: |
| 427 RegisterFilesystemEventListeners() { |
| 428 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 429 |
| 430 PluginEventRouter *router = PluginEventRouter::GetInstance(); |
| 431 if (router!=nullptr) |
| 432 router->AddEventsListener( events_, this, filesystem_info_.plugin_name ); |
| 433 } |
| 434 // Remove all events from the PluginEventRouter list of dispatchable events |
| 435 void PepperFilesystemProviderBackendChromeOS:: |
| 436 UnregisterFilesystemEventListeners() { |
| 437 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 438 PluginEventRouter *router = PluginEventRouter::GetInstance(); |
| 439 if (router!=nullptr) |
| 440 router->RemoveEventsListeners( events_, this, filesystem_info_.plugin_name); |
| 441 } |
| 442 |
| 443 // Static |
| 444 // Responsible with the creations and registration of a new provided filesystem |
| 445 base::File::Error PepperFilesystemProviderBackendChromeOS:: |
| 446 RegisterFilesystemOnUI( |
| 447 ProvidedFilesystemInfo filesystem_info) |
| 448 { |
| 449 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 450 |
| 451 Service *fs_service = Service::Get(ProfileManager::GetActiveUserProfile()); |
| 452 DCHECK(fs_service); |
| 453 |
| 454 chromeos::file_system_provider::MountOptions options( |
| 455 filesystem_info.filesystem_id, filesystem_info.display_name); |
| 456 |
| 457 options.writable = filesystem_info.writable; |
| 458 options.opened_files_limit = filesystem_info.opened_files_limit; |
| 459 options.supports_notify_tag = false; // Check this |
| 460 |
| 461 base::File::Error error = fs_service->MountFileSystem( |
| 462 filesystem_info.plugin_name, |
| 463 options, |
| 464 Source_Type::plugin ); |
| 465 |
| 466 return error; // This will be interpreted by MountReplyOnIO |
| 467 } |
| 468 |
| 469 // Sends feedback to the plugin |
| 470 // and sets state |
| 471 void PepperFilesystemProviderBackendChromeOS::MountReplyOnIO( |
| 472 ppapi::host::ReplyMessageContext reply_msg, |
| 473 ProvidedFilesystemInfo filesystem_info, |
| 474 base::File::Error err) { |
| 475 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 476 |
| 477 // Do not register and send error back |
| 478 if ( err != base::File::FILE_OK ) { |
| 479 reply_msg.params.set_result(PP_OK); |
| 480 host_->SendReply( |
| 481 reply_msg, |
| 482 PpapiPluginMsg_FilesystemProvider_MountReply( PP_ProviderError_FAILED ) |
| 483 ); |
| 484 return; |
| 485 } |
| 486 |
| 487 filesystem_info_.writable = filesystem_info.writable; |
| 488 filesystem_info_.opened_files_limit = filesystem_info.opened_files_limit; |
| 489 filesystem_info_.filesystem_id = filesystem_info.filesystem_id; |
| 490 filesystem_info_.display_name = filesystem_info.display_name; |
| 491 mounted_ = true; |
| 492 |
| 493 // Initialize the shared memory buffers if needed |
| 494 if (!read_write_buffer_.get()) |
| 495 InitializeMemoryBuffer(); |
| 496 RegisterFilesystemEventListeners(); |
| 497 |
| 498 reply_msg.params.set_result(PP_OK); |
| 499 host_->SendReply( |
| 500 reply_msg, |
| 501 PpapiPluginMsg_FilesystemProvider_MountReply( PP_ProviderError_OK ) |
| 502 ); |
| 503 } |
| 504 |
| 505 //static |
| 506 // Responsible with removal of the filesystem backend |
| 507 base::File::Error PepperFilesystemProviderBackendChromeOS:: |
| 508 UnregisterFilesystemOnUI( |
| 509 ProvidedFilesystemInfo filesystem_info) { |
| 510 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 511 |
| 512 Service *fs_service = Service::Get(ProfileManager::GetActiveUserProfile()); |
| 513 DCHECK(fs_service); |
| 514 |
| 515 base::File::Error err = fs_service->UnmountFileSystem( |
| 516 filesystem_info.plugin_name, |
| 517 filesystem_info.filesystem_id, |
| 518 chromeos::file_system_provider::Service::UNMOUNT_REASON_USER ); |
| 519 |
| 520 return err; |
| 521 } |
| 522 |
| 523 // Sends feedback to the plugin |
| 524 // and resets state |
| 525 void PepperFilesystemProviderBackendChromeOS::UnmountReplyOnIO( |
| 526 ppapi::host::ReplyMessageContext reply_msg, base::File::Error err) { |
| 527 |
| 528 reply_msg.params.set_result(PP_OK); |
| 529 // Unregister all events |
| 530 UnregisterFilesystemEventListeners(); |
| 531 |
| 532 mounted_ = false; |
| 533 filesystem_info_.writable = false; |
| 534 filesystem_info_.opened_files_limit = 0; |
| 535 filesystem_info_.filesystem_id = ""; |
| 536 filesystem_info_.display_name = ""; |
| 537 |
| 538 // Send result to the plugin |
| 539 host_->SendReply( |
| 540 reply_msg, |
| 541 PpapiPluginMsg_FilesystemProvider_MountReply( PP_ProviderError_OK ) |
| 542 ); |
| 543 } |
| 544 |
| 545 // Handle events that are dispatched by the PluginEventRouter |
| 546 void PepperFilesystemProviderBackendChromeOS::OnDispatchEvent( |
| 547 std::string event_name, scoped_ptr<base::ListValue> event_args) { |
| 548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 549 |
| 550 ListOfHandlersIterator it = handlers_list_.find( event_name ); |
| 551 if ( it != handlers_list_.end() ) |
| 552 it->second.first.Run( it->second.second, event_args.Pass() ); |
| 553 } |
| 554 |
| 555 // Sends requests to plugin |
| 556 void PepperFilesystemProviderBackendChromeOS::SendOperationRequestToPlugin( |
| 557 PP_OperationType_Dev operation_type, |
| 558 scoped_ptr<base::ListValue> event_args) { |
| 559 |
| 560 //TODO(sabin): Remove this when done testing |
| 561 if(operation_type==PP_OperationType_OPENFILE) |
| 562 time_stamp_=std::chrono::system_clock::now(); |
| 563 else if(operation_type==PP_OperationType_CLOSEFILE) { |
| 564 std::chrono::duration<double> elapsed_seconds = |
| 565 std::chrono::system_clock::now()-time_stamp_; |
| 566 LOG(ERROR) <<"Read/Write operation time: "<< elapsed_seconds.count()<< |
| 567 " seconds"; |
| 568 } |
| 569 |
| 570 host_->SendUnsolicitedReply( |
| 571 resource_, |
| 572 PpapiPluginMsg_FilesystemProvider_OperationRequest( |
| 573 operation_type, |
| 574 *event_args) |
| 575 ); |
| 576 |
| 577 } |
| 578 |
| 579 void PepperFilesystemProviderBackendChromeOS::SendWriteRequestToPlugin( |
| 580 PP_OperationType_Dev operation_type, |
| 581 scoped_ptr<base::ListValue> request) { |
| 582 // Handle write to filesystem |
| 583 // Put the chunk into the shared memory buffer or cache it |
| 584 // if channel is not free |
| 585 // TODO(sabin): Send error back to backend if this fails |
| 586 write_channel_controller_->EnqueueRequest(request.Pass()); |
| 587 } |
| 588 |
| 589 // Transforms messages that are received from |
| 590 // the plugin in response of filesystem operations and sends |
| 591 // them back to the filesystem backend. |
| 592 int32_t PepperFilesystemProviderBackendChromeOS::OnGeneralSuccessResponse( |
| 593 int operation, |
| 594 ProvidedFilesystemInfo filesystem_info, |
| 595 scoped_ptr<base::ListValue> args) { |
| 596 |
| 597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 598 Service *fs_service = Service::Get(ProfileManager::GetActiveUserProfile()); |
| 599 DCHECK(fs_service); |
| 600 |
| 601 ProvidedFileSystemInterface* fs_interface = |
| 602 fs_service->GetProvidedFileSystem( |
| 603 filesystem_info.plugin_name, |
| 604 filesystem_info.filesystem_id); |
| 605 |
| 606 if (fs_interface==nullptr) |
| 607 return PP_ERROR_FAILED; |
| 608 |
| 609 switch(operation) { |
| 610 case PP_OperationType_READDIRECTORY: { |
| 611 using extensions::api:: |
| 612 file_system_provider_internal::ReadDirectoryRequestedSuccess:: |
| 613 Params; |
| 614 scoped_ptr<Params> params(Params::Create(*args)); |
| 615 if(!params.get()) |
| 616 return PP_ERROR_FAILED; |
| 617 |
| 618 const bool has_more = params->has_more; |
| 619 if ( base::File::FILE_OK!= |
| 620 fs_interface->GetRequestManager()->FulfillRequest( |
| 621 params->request_id, |
| 622 chromeos::file_system_provider::RequestValue:: |
| 623 CreateForReadDirectorySuccess(params.Pass()), |
| 624 has_more) |
| 625 ) |
| 626 return PP_ERROR_FAILED; |
| 627 } |
| 628 break; |
| 629 case PP_OperationType_GETMETADATA: { |
| 630 using extensions::api::file_system_provider_internal:: |
| 631 GetMetadataRequestedSuccess::Params; |
| 632 scoped_ptr<Params> params(Params::Create(*args)); |
| 633 if(!params.get()) |
| 634 return PP_ERROR_FAILED; |
| 635 |
| 636 if (base::File::FILE_OK!= |
| 637 fs_interface->GetRequestManager()->FulfillRequest( |
| 638 params->request_id, |
| 639 chromeos::file_system_provider::RequestValue:: |
| 640 CreateForGetMetadataSuccess(params.Pass()), |
| 641 false) |
| 642 ) |
| 643 return PP_ERROR_FAILED; |
| 644 } |
| 645 break; |
| 646 case PP_OperationType_READFILE: { |
| 647 using extensions::api::file_system_provider_internal:: |
| 648 ReadFileRequestedSuccess::Params; |
| 649 scoped_ptr<Params> params(Params::Create(*args)); |
| 650 if (!params.get()) |
| 651 return PP_ERROR_FAILED; |
| 652 |
| 653 const bool has_more = params->has_more; |
| 654 if (base::File::FILE_OK!= |
| 655 fs_interface->GetRequestManager()->FulfillRequest( |
| 656 params->request_id, |
| 657 chromeos::file_system_provider::RequestValue:: |
| 658 CreateForReadFileSuccess(params.Pass()), |
| 659 has_more) ) |
| 660 return PP_ERROR_FAILED; |
| 661 } |
| 662 break; |
| 663 case PP_OperationType_UNMOUNT: { |
| 664 using extensions::api::file_system_provider_internal:: |
| 665 UnmountRequestedSuccess::Params; |
| 666 scoped_ptr<Params> params(Params::Create(*args)); |
| 667 if(!params.get()) |
| 668 return PP_ERROR_FAILED; |
| 669 |
| 670 if (base::File::FILE_OK!= |
| 671 fs_service->UnmountFileSystem( |
| 672 filesystem_info.plugin_name, filesystem_info.filesystem_id, |
| 673 chromeos::file_system_provider::Service::UNMOUNT_REASON_USER) |
| 674 ) |
| 675 return PP_ERROR_FAILED; |
| 676 } |
| 677 break; |
| 678 default: { |
| 679 using extensions::api::file_system_provider_internal:: |
| 680 OperationRequestedSuccess::Params; |
| 681 scoped_ptr<Params> params(Params::Create(*args)); |
| 682 if(!params.get()) |
| 683 return PP_ERROR_FAILED; |
| 684 |
| 685 if (base::File::FILE_OK!= |
| 686 fs_interface->GetRequestManager()->FulfillRequest( |
| 687 params->request_id, |
| 688 chromeos::file_system_provider::RequestValue:: |
| 689 CreateForOperationSuccess(params.Pass()), |
| 690 false) |
| 691 ) |
| 692 return PP_ERROR_FAILED; |
| 693 } |
| 694 break; |
| 695 } |
| 696 return PP_OK; |
| 697 } |
| 698 |
| 699 int32_t PepperFilesystemProviderBackendChromeOS::OnGeneralErrorResponse( |
| 700 ProvidedFilesystemInfo filesystem_info, |
| 701 scoped_ptr<base::ListValue> args) { |
| 702 |
| 703 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 704 |
| 705 Service *fs_service = Service::Get(ProfileManager::GetActiveUserProfile()); |
| 706 DCHECK(fs_service); |
| 707 |
| 708 ProvidedFileSystemInterface* fs_interface = |
| 709 fs_service->GetProvidedFileSystem( |
| 710 filesystem_info.plugin_name, |
| 711 filesystem_info.filesystem_id); |
| 712 if(fs_interface==nullptr) |
| 713 return PP_ERROR_FAILED; |
| 714 |
| 715 using extensions::api::file_system_provider_internal:: |
| 716 OperationRequestedError::Params; |
| 717 scoped_ptr<Params> params(Params::Create(*args)); |
| 718 if(!params.get()) |
| 719 return PP_ERROR_FAILED; |
| 720 |
| 721 const base::File::Error error = PP_ProviderErrorToFileError(params->error); |
| 722 |
| 723 if( base::File::FILE_OK!= |
| 724 fs_interface->GetRequestManager()->RejectRequest( |
| 725 params->request_id, |
| 726 chromeos::file_system_provider::RequestValue:: |
| 727 CreateForOperationError(params.Pass()), |
| 728 error) |
| 729 ) |
| 730 return PP_ERROR_FAILED; |
| 731 return PP_OK; |
| 732 } |
| 733 |
| 734 bool PepperFilesystemProviderBackendChromeOS::FlushRequest( |
| 735 scoped_ptr<base::ListValue> request) { |
| 736 if(!request.get()) |
| 737 return false; |
| 738 |
| 739 if(!AddFromMessageToSharedMemory(*request)) |
| 740 return false; |
| 741 |
| 742 host_->SendUnsolicitedReply( |
| 743 resource_, |
| 744 PpapiPluginMsg_FilesystemProvider_OperationRequest( |
| 745 PP_OperationType_WRITEFILE, |
| 746 *request)); |
| 747 return true; |
| 748 } |
| 749 |
| 750 bool PepperFilesystemProviderBackendChromeOS::InitializeMemoryBuffer() { |
| 751 // Already initialized |
| 752 if(read_write_buffer_.get()) |
| 753 return false; |
| 754 scoped_ptr<base::SharedMemory> buffer( new base::SharedMemory ); |
| 755 size_t size = kReaderBufferSize + kWriterBufferSize; |
| 756 if (!buffer.get() || |
| 757 !buffer->CreateAndMapAnonymous(size)) |
| 758 return false; |
| 759 read_write_buffer_=make_scoped_ptr(new ShmBuffer(size, buffer.Pass())); |
| 760 if(!read_write_buffer_.get()) |
| 761 return false; |
| 762 using ppapi::proxy::SerializedHandle; |
| 763 std::vector<SerializedHandle> handles; |
| 764 handles.push_back( |
| 765 SerializedHandle(read_write_buffer_->shm->handle(), size )); |
| 766 // Send a message to the plugin with the shared mem handle |
| 767 host_->SendUnsolicitedReplyWithHandles( |
| 768 resource_, |
| 769 PpapiPluginMsg_FilesystemProvider_Buffers( |
| 770 kReaderBufferSize, |
| 771 kWriterBufferSize), |
| 772 handles |
| 773 ); |
| 774 return true; |
| 775 } |
| 776 bool PepperFilesystemProviderBackendChromeOS::AddFromSharedMemoryToMessage( |
| 777 base::ListValue& message) { |
| 778 DCHECK(read_write_buffer_.get()); |
| 779 double out = 0; |
| 780 if(!message.GetDouble(2,&out)) |
| 781 return false; |
| 782 size_t out_size = out; |
| 783 if(out_size>kReaderBufferSize) |
| 784 return false; |
| 785 |
| 786 // Replace the size with the actual data |
| 787 return message.Set(2, base::BinaryValue::CreateWithCopiedBuffer( |
| 788 (const char*)read_write_buffer_->shm->memory(), out_size)); |
| 789 } |
| 790 |
| 791 bool PepperFilesystemProviderBackendChromeOS::AddFromMessageToSharedMemory( |
| 792 base::ListValue& message) { |
| 793 if( !read_write_buffer_.get() ) |
| 794 return false; |
| 795 |
| 796 base::Value *dict_value = nullptr; |
| 797 if(!message.Get(0,&dict_value)) |
| 798 return false; |
| 799 |
| 800 base::DictionaryValue* dict = |
| 801 static_cast<base::DictionaryValue*>(dict_value); |
| 802 const base::BinaryValue* binary_value = NULL; |
| 803 if (!dict->GetBinary("data", &binary_value)) |
| 804 return false; |
| 805 // This can be '0' |
| 806 size_t binary_size =binary_value->GetSize(); |
| 807 // Skip the read buffer and copy to shared mem the buffer into |
| 808 // the write portion of the buffer |
| 809 if(binary_size>kWriterBufferSize) |
| 810 return false; |
| 811 memcpy( (char*)read_write_buffer_->shm->memory()+kReaderBufferSize, |
| 812 binary_value->GetBuffer(), |
| 813 binary_size); |
| 814 dict->Remove( "data", nullptr ); |
| 815 dict->SetDouble( "size",binary_size); |
| 816 return true; |
| 817 } |
| 818 |
| 819 scoped_ptr<MountOperationTranslator> |
| 820 MountOperationTranslator::PopulateFromResponse( |
| 821 const base::ListValue& request) { |
| 822 const base::Value *dict_value = nullptr; |
| 823 if(!request.Get(0,&dict_value)) |
| 824 return scoped_ptr<MountOperationTranslator>(); |
| 825 |
| 826 const base::DictionaryValue* dict = |
| 827 static_cast<const base::DictionaryValue*>(dict_value); |
| 828 |
| 829 scoped_ptr< MountOperationTranslator > out(new MountOperationTranslator); |
| 830 |
| 831 const base::Value* data_value = nullptr; |
| 832 if (!dict->GetWithoutPathExpansion("fileSystemId", &data_value) || |
| 833 !data_value->IsType(base::Value::TYPE_STRING)) |
| 834 return scoped_ptr<MountOperationTranslator>(); |
| 835 if (!data_value->GetAsString(&out->file_system_id)) |
| 836 return scoped_ptr<MountOperationTranslator>(); |
| 837 if (!dict->GetWithoutPathExpansion("displayName", &data_value) || |
| 838 !data_value->IsType(base::Value::TYPE_STRING)) |
| 839 return scoped_ptr<MountOperationTranslator>(); |
| 840 if (!data_value->GetAsString(&out->display_name)) |
| 841 return scoped_ptr<MountOperationTranslator>(); |
| 842 if (!dict->GetWithoutPathExpansion("writable", &data_value) || |
| 843 !data_value->IsType(base::Value::TYPE_BOOLEAN)) |
| 844 return scoped_ptr<MountOperationTranslator>(); |
| 845 if (!data_value->GetAsBoolean(&out->writable)) |
| 846 return scoped_ptr<MountOperationTranslator>(); |
| 847 |
| 848 if (!dict->GetWithoutPathExpansion("openedFilesLimit", &data_value) || |
| 849 !data_value->IsType(base::Value::TYPE_INTEGER)) |
| 850 return scoped_ptr<MountOperationTranslator>(); |
| 851 if (!data_value->GetAsInteger(&out->opened_files_limit)) |
| 852 return scoped_ptr<MountOperationTranslator>(); |
| 853 |
| 854 return out.Pass(); |
| 855 } |
| 856 |
| 857 }// namespace content |
| 858 |
OLD | NEW |