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/file_system_plugin/plugin
_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 namespace chromeos::file_system_provider; |
| 21 using content::BrowserThread; |
| 22 using ppapi::host::HostMessageContext; |
| 23 |
| 24 namespace content { |
| 25 |
| 26 namespace { |
| 27 |
| 28 // TODO(sabin): find a way to get the size of the stream reader internal |
| 29 // buffer from the backend |
| 30 // Size of the stream reader internal buffer. At most this number of bytes will |
| 31 // be read ahead of the requested data. |
| 32 const uint32_t kReaderBufferSize = 512 * 1024; // 512KB. |
| 33 |
| 34 // Size of the stream writer internal buffer. At most this number of bytes will |
| 35 // be postponed for writing. |
| 36 const uint32_t kWriterBufferSize = 512 * 1024; // 512KB. |
| 37 |
| 38 // The number of requests that can be buffered |
| 39 const uint32_t kMaximumCachedReplies = 10; |
| 40 |
| 41 RequestType PP_OperationToRequestType(int32_t operation_type) { |
| 42 switch (operation_type) { |
| 43 case PP_OperationType_ABORT: |
| 44 return ABORT; |
| 45 case PP_OperationType_ADDWATCHER: |
| 46 return ADD_WATCHER; |
| 47 case PP_OperationType_CLOSEFILE: |
| 48 return CLOSE_FILE; |
| 49 case PP_OperationType_COPYENTRY: |
| 50 return COPY_ENTRY; |
| 51 case PP_OperationType_CREATEDIRECTORY: |
| 52 return CREATE_DIRECTORY; |
| 53 case PP_OperationType_CREATEFILE: |
| 54 return CREATE_FILE; |
| 55 case PP_OperationType_DELETEENTRY: |
| 56 return DELETE_ENTRY; |
| 57 case PP_OperationType_GETMETADATA: |
| 58 return GET_METADATA; |
| 59 case PP_OperationType_MOVEENTRY: |
| 60 return MOVE_ENTRY; |
| 61 case PP_OperationType_OPENFILE: |
| 62 return OPEN_FILE; |
| 63 case PP_OperationType_READDIRECTORY: |
| 64 return READ_DIRECTORY; |
| 65 case PP_OperationType_READFILE: |
| 66 return READ_FILE; |
| 67 case PP_OperationType_REMOVEWATCHER: |
| 68 return REMOVE_WATCHER; |
| 69 case PP_OperationType_TRUNCATEENTRY: |
| 70 return TRUNCATE; |
| 71 case PP_OperationType_UNMOUNT: |
| 72 return REQUEST_UNMOUNT; |
| 73 case PP_OperationType_WRITEFILE: |
| 74 return WRITE_FILE; |
| 75 case PP_OperationType_NONE: |
| 76 default: |
| 77 break; |
| 78 } |
| 79 NOTREACHED(); |
| 80 return ABORT; |
| 81 } |
| 82 |
| 83 PP_OperationType_Dev RequestTypeToOperationType(int32_t operation_type) { |
| 84 switch (operation_type) { |
| 85 case ABORT: |
| 86 return PP_OperationType_ABORT; |
| 87 case ADD_WATCHER: |
| 88 return PP_OperationType_ADDWATCHER; |
| 89 case CLOSE_FILE: |
| 90 return PP_OperationType_CLOSEFILE; |
| 91 case COPY_ENTRY: |
| 92 return PP_OperationType_COPYENTRY; |
| 93 case CREATE_DIRECTORY: |
| 94 return PP_OperationType_CREATEDIRECTORY; |
| 95 case CREATE_FILE: |
| 96 return PP_OperationType_CREATEFILE; |
| 97 case DELETE_ENTRY: |
| 98 return PP_OperationType_DELETEENTRY; |
| 99 case GET_METADATA: |
| 100 return PP_OperationType_GETMETADATA; |
| 101 case MOVE_ENTRY: |
| 102 return PP_OperationType_MOVEENTRY; |
| 103 case OPEN_FILE: |
| 104 return PP_OperationType_OPENFILE; |
| 105 case READ_DIRECTORY: |
| 106 return PP_OperationType_READDIRECTORY; |
| 107 case READ_FILE: |
| 108 return PP_OperationType_READFILE; |
| 109 case REMOVE_WATCHER: |
| 110 return PP_OperationType_REMOVEWATCHER; |
| 111 case TRUNCATE: |
| 112 return PP_OperationType_TRUNCATEENTRY; |
| 113 case REQUEST_UNMOUNT: |
| 114 return PP_OperationType_UNMOUNT; |
| 115 case WRITE_FILE: |
| 116 return PP_OperationType_WRITEFILE; |
| 117 default: |
| 118 break; |
| 119 } |
| 120 NOTREACHED(); |
| 121 return PP_OperationType_NONE; |
| 122 } |
| 123 |
| 124 } // namespace |
| 125 |
| 126 PepperFilesystemProviderBackendChromeOS:: |
| 127 ProvidedFilesystemInfo::ProvidedFilesystemInfo() |
| 128 :filesystem_id("none"), |
| 129 display_name("none"), |
| 130 plugin_name("none"), |
| 131 writable(false), |
| 132 opened_files_limit(0) { |
| 133 } |
| 134 PepperFilesystemProviderBackendChromeOS::ShmBuffer::ShmBuffer( |
| 135 uint32_t size, scoped_ptr<base::SharedMemory> shm) |
| 136 : size(size),shm(shm.Pass()) { |
| 137 DCHECK(this->shm); |
| 138 } |
| 139 |
| 140 PepperFilesystemProviderBackendChromeOS::ShmBuffer::~ShmBuffer() { |
| 141 |
| 142 } |
| 143 |
| 144 PepperFilesystemProviderBackendChromeOS:: |
| 145 ShmChannelController::ShmChannelController( |
| 146 uint32_t size, FlushRequestCallback callback) |
| 147 : max_size(size), |
| 148 ready(true), |
| 149 callback(callback){ |
| 150 } |
| 151 PepperFilesystemProviderBackendChromeOS:: |
| 152 ShmChannelController::~ShmChannelController() { |
| 153 } |
| 154 |
| 155 bool PepperFilesystemProviderBackendChromeOS:: |
| 156 ShmChannelController::EnqueueRequest( |
| 157 scoped_ptr<base::ListValue> response) { |
| 158 // If channel ready send it straight away |
| 159 if(ready) { |
| 160 ready = !callback.Run(response.Pass()); |
| 161 if(!ready) |
| 162 return true; |
| 163 } |
| 164 // If channel is not ready or failed to send |
| 165 // cache the request |
| 166 if(size() + 1 > max_size) |
| 167 return false; |
| 168 replies.push_back( response.Pass() ); |
| 169 return true; |
| 170 } |
| 171 |
| 172 bool PepperFilesystemProviderBackendChromeOS:: |
| 173 ShmChannelController::PushNextRequest() { |
| 174 // Try and send the request |
| 175 scoped_ptr<base::ListValue> response; |
| 176 while (size()>0 && ready ) { |
| 177 response.reset(replies.front()); |
| 178 replies.weak_erase(replies.begin()); |
| 179 ready = !callback.Run(response.Pass()); |
| 180 } |
| 181 return !ready; |
| 182 } |
| 183 |
| 184 bool |
| 185 PepperFilesystemProviderBackendChromeOS:: |
| 186 ShmChannelController::AckLastPushedRequest() { |
| 187 return ready = true; |
| 188 } |
| 189 |
| 190 uint32_t PepperFilesystemProviderBackendChromeOS:: |
| 191 ShmChannelController::size() { |
| 192 return replies.size(); |
| 193 } |
| 194 |
| 195 |
| 196 |
| 197 PepperFilesystemProviderBackendChromeOS:: |
| 198 PepperFilesystemProviderBackendChromeOS( |
| 199 content::BrowserPpapiHost *host, |
| 200 PP_Instance instance, |
| 201 PP_Resource resource) |
| 202 : mounted_(false), |
| 203 host_(host ? host->GetPpapiHost() : nullptr), |
| 204 resource_(resource), |
| 205 write_channel_controller_(new ShmChannelController( |
| 206 kMaximumCachedReplies, |
| 207 base::Bind( |
| 208 &PepperFilesystemProviderBackendChromeOS:: |
| 209 FlushRequest, |
| 210 base::Unretained(this)))), |
| 211 weak_factory_(this) { |
| 212 |
| 213 filesystem_info_.plugin_name = std::string("Plugin_") + |
| 214 std::to_string(static_cast<size_t>(instance)); |
| 215 } |
| 216 |
| 217 PepperFilesystemProviderBackendChromeOS:: |
| 218 ~PepperFilesystemProviderBackendChromeOS() { |
| 219 // Unregister the filesystem if state indicates |
| 220 // that we have a mounted filesystem |
| 221 if (mounted_) { |
| 222 // Unregister any registered event from the PluginEventRouter |
| 223 UnregisterFilesystemListenedOperations(); |
| 224 // Unregister the filesystem backend on the |
| 225 // proper thread from Service |
| 226 BrowserThread::PostTask( |
| 227 BrowserThread::UI, |
| 228 FROM_HERE, |
| 229 base::Bind( |
| 230 base::IgnoreResult( |
| 231 &PepperFilesystemProviderBackendChromeOS:: |
| 232 UnregisterFilesystemOnUI), |
| 233 filesystem_info_ |
| 234 ) |
| 235 ); |
| 236 } |
| 237 } |
| 238 |
| 239 // Called when PpapiHostMsg_FilesystemProvider_Mount is received |
| 240 // Forwards request to RegisterFilesystemOnUI |
| 241 // Response is sent from MountReplyOnIO |
| 242 int32_t PepperFilesystemProviderBackendChromeOS::SendMountRequest( |
| 243 ppapi::host::HostMessageContext *context, |
| 244 const base::ListValue& request) { |
| 245 using content::filesystem_provider_internal::MountOperationTranslator; |
| 246 |
| 247 base::File::Error status = base::File::FILE_OK; |
| 248 if (mounted_) |
| 249 status = base::File::FILE_ERROR_EXISTS; |
| 250 |
| 251 scoped_ptr<MountOperationTranslator> mount_info = |
| 252 MountOperationTranslator::PopulateFromResponse(request); |
| 253 if ( !mount_info.get() ) |
| 254 status = base::File::FILE_ERROR_FAILED; |
| 255 |
| 256 // Stop and send failure back to the plugin |
| 257 if (status!=base::File::FILE_OK) { |
| 258 MountReplyOnIO( |
| 259 context->MakeReplyMessageContext(), |
| 260 filesystem_info_, base::File::FILE_ERROR_EXISTS); |
| 261 return PP_OK_COMPLETIONPENDING; |
| 262 } |
| 263 // Populate the desired filesystem configuration |
| 264 ProvidedFilesystemInfo filesystem_info; |
| 265 filesystem_info.writable = mount_info->writable; |
| 266 filesystem_info.display_name = mount_info->display_name; |
| 267 filesystem_info.plugin_name = filesystem_info_.plugin_name; |
| 268 filesystem_info.filesystem_id = mount_info->file_system_id; |
| 269 filesystem_info.opened_files_limit = mount_info->opened_files_limit; |
| 270 // Change thread to create the filesystem backend on the |
| 271 // UI thread. The result of this action is to be interpreted |
| 272 // on the IO thread. |
| 273 BrowserThread::PostTaskAndReplyWithResult( |
| 274 BrowserThread::UI, |
| 275 FROM_HERE, |
| 276 base::Bind( |
| 277 // This creates a filesystem backend owned by the Service |
| 278 // entity |
| 279 &PepperFilesystemProviderBackendChromeOS::RegisterFilesystemOnUI, |
| 280 filesystem_info), |
| 281 // This is called after the above returns to interpret result |
| 282 base::Bind( |
| 283 &PepperFilesystemProviderBackendChromeOS::MountReplyOnIO, |
| 284 weak_factory_.GetWeakPtr(), |
| 285 context->MakeReplyMessageContext(), |
| 286 filesystem_info |
| 287 ) |
| 288 ); |
| 289 return PP_OK_COMPLETIONPENDING; |
| 290 } |
| 291 |
| 292 // Called when PpapiHostMsg_FilesystemProvider_Unmount is received |
| 293 // Forwards request to UnregisterFilesystemOnUI |
| 294 // Response is sent from MountReplyOnIO |
| 295 int32_t PepperFilesystemProviderBackendChromeOS::SendUnmountRequest( |
| 296 ppapi::host::HostMessageContext *context, const std::string& fsid) { |
| 297 |
| 298 if(!mounted_) { |
| 299 return PP_ERROR_FAILED; |
| 300 } |
| 301 |
| 302 // Remove registered events from PluginEventRouter |
| 303 UnregisterFilesystemListenedOperations(); |
| 304 |
| 305 BrowserThread::PostTaskAndReplyWithResult( |
| 306 BrowserThread::UI, |
| 307 FROM_HERE, |
| 308 base::Bind( |
| 309 &PepperFilesystemProviderBackendChromeOS::UnregisterFilesystemOnUI, |
| 310 filesystem_info_), |
| 311 base::Bind( &PepperFilesystemProviderBackendChromeOS::UnmountReplyOnIO, |
| 312 weak_factory_.GetWeakPtr(), |
| 313 context->MakeReplyMessageContext()) |
| 314 ); |
| 315 return PP_OK_COMPLETIONPENDING; |
| 316 } |
| 317 |
| 318 int32_t PepperFilesystemProviderBackendChromeOS::OnPluginResponse( |
| 319 ppapi::host::HostMessageContext* context, |
| 320 const base::ListValue& plugin_response) { |
| 321 scoped_ptr<base::ListValue> response( plugin_response.DeepCopy() ); |
| 322 |
| 323 if (!response.get() || |
| 324 !mounted_) |
| 325 return PP_ERROR_FAILED; |
| 326 |
| 327 bool status; |
| 328 int operation_type = PP_OperationType_NONE; |
| 329 if (!PreprocessMessage(*response, status, operation_type)) |
| 330 return PP_ERROR_FAILED; |
| 331 if ( status ) {// success |
| 332 BrowserThread::PostTask( |
| 333 BrowserThread::UI, |
| 334 FROM_HERE, |
| 335 base::Bind( |
| 336 base::IgnoreResult( |
| 337 &PepperFilesystemProviderBackendChromeOS:: |
| 338 OnSuccessResponse), |
| 339 operation_type, |
| 340 filesystem_info_, |
| 341 base::Passed(response.Pass())) |
| 342 ); |
| 343 } else { // failure |
| 344 BrowserThread::PostTask( |
| 345 BrowserThread::UI, |
| 346 FROM_HERE, |
| 347 base::Bind( |
| 348 base::IgnoreResult( |
| 349 &PepperFilesystemProviderBackendChromeOS:: |
| 350 OnErrorResponse), |
| 351 filesystem_info_, |
| 352 base::Passed(response.Pass())) |
| 353 ); |
| 354 } |
| 355 |
| 356 return PP_OK; |
| 357 } |
| 358 |
| 359 // Sends next cached request if there is any pending |
| 360 int32_t PepperFilesystemProviderBackendChromeOS::OnPluginWriteAck( |
| 361 ppapi::host::HostMessageContext* ) { |
| 362 write_channel_controller_->AckLastPushedRequest(); |
| 363 write_channel_controller_->PushNextRequest(); |
| 364 return PP_OK; |
| 365 } |
| 366 |
| 367 int32_t PepperFilesystemProviderBackendChromeOS::OnPluginNotification( |
| 368 ppapi::host::HostMessageContext* context, const base::ListValue& args) { |
| 369 scoped_ptr<base::ListValue> message(args.DeepCopy()); |
| 370 BrowserThread::PostTask( |
| 371 BrowserThread::UI, |
| 372 FROM_HERE, |
| 373 base::Bind( |
| 374 &PepperFilesystemProviderBackendChromeOS:: |
| 375 SendNotificationOnUI, |
| 376 filesystem_info_, base::Passed(message.Pass()) |
| 377 ) |
| 378 ); |
| 379 return PP_OK; |
| 380 } |
| 381 |
| 382 void OnNotifyCompleted(base::File::Error /*result*/) {} |
| 383 |
| 384 void PepperFilesystemProviderBackendChromeOS::SendNotificationOnUI( |
| 385 const ProvidedFilesystemInfo& file_system_info, |
| 386 scoped_ptr<base::ListValue> args) { |
| 387 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 388 |
| 389 PluginService *fs_service = PluginService::Get( |
| 390 ProfileManager::GetActiveUserProfile()); |
| 391 DCHECK(fs_service); |
| 392 |
| 393 ProvidedFileSystemAdapter* fs_backend = |
| 394 fs_service->GetProvidedFileSystemAdapter( |
| 395 file_system_info.plugin_name, |
| 396 file_system_info.filesystem_id); |
| 397 if (!fs_backend) |
| 398 return; |
| 399 fs_backend->PushChangeNotificationResponse(args.Pass(), |
| 400 base::Bind(OnNotifyCompleted)); |
| 401 } |
| 402 |
| 403 // Add all events to the PluginEventRouter list of dispatchable events |
| 404 void PepperFilesystemProviderBackendChromeOS:: |
| 405 RegisterFilesystemListenedOperations() { |
| 406 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 407 std::vector<RequestType> operations = { |
| 408 REQUEST_UNMOUNT, GET_METADATA, READ_DIRECTORY, OPEN_FILE, CLOSE_FILE, |
| 409 READ_FILE, CREATE_DIRECTORY, DELETE_ENTRY, CREATE_FILE, COPY_ENTRY, |
| 410 MOVE_ENTRY, TRUNCATE, WRITE_FILE, ABORT, ADD_WATCHER, REMOVE_WATCHER |
| 411 }; |
| 412 PluginOperationRouter *router = PluginOperationRouter::GetInstance(); |
| 413 if (router!=nullptr) |
| 414 router->AddOperationsForListener( operations, this, |
| 415 filesystem_info_.plugin_name ); |
| 416 } |
| 417 using chromeos::file_system_provider::READ_DIRECTORY; |
| 418 // Remove all events from the PluginEventRouter list of dispatchable events |
| 419 void PepperFilesystemProviderBackendChromeOS:: |
| 420 UnregisterFilesystemListenedOperations() { |
| 421 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 422 std::vector<RequestType> operations = { |
| 423 REQUEST_UNMOUNT, GET_METADATA, READ_DIRECTORY, OPEN_FILE, CLOSE_FILE, |
| 424 READ_FILE, CREATE_DIRECTORY, DELETE_ENTRY, CREATE_FILE, COPY_ENTRY, |
| 425 MOVE_ENTRY, TRUNCATE, WRITE_FILE, ABORT, ADD_WATCHER, REMOVE_WATCHER |
| 426 }; |
| 427 PluginOperationRouter *router = PluginOperationRouter::GetInstance(); |
| 428 if (router!=nullptr) |
| 429 router->RemoveOperationsForListener(operations, |
| 430 filesystem_info_.plugin_name); |
| 431 } |
| 432 |
| 433 // Static |
| 434 // Responsible with the creations and registration of a new provided filesystem |
| 435 base::File::Error PepperFilesystemProviderBackendChromeOS:: |
| 436 RegisterFilesystemOnUI( |
| 437 ProvidedFilesystemInfo filesystem_info) |
| 438 { |
| 439 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 440 |
| 441 PluginService *fs_service = PluginService::Get( |
| 442 ProfileManager::GetActiveUserProfile()); |
| 443 DCHECK(fs_service); |
| 444 |
| 445 chromeos::file_system_provider::MountOptions options( |
| 446 filesystem_info.filesystem_id, filesystem_info.display_name); |
| 447 |
| 448 // TODO(sabin): add support for watchers |
| 449 options.supports_notify_tag = false; |
| 450 options.writable = filesystem_info.writable; |
| 451 options.opened_files_limit = filesystem_info.opened_files_limit; |
| 452 |
| 453 base::File::Error error = fs_service->MountFileSystem( |
| 454 filesystem_info.plugin_name, |
| 455 options); |
| 456 |
| 457 return error; // This will be interpreted by MountReplyOnIO |
| 458 } |
| 459 |
| 460 // Sends feedback to the plugin |
| 461 // and sets state |
| 462 void PepperFilesystemProviderBackendChromeOS::MountReplyOnIO( |
| 463 ppapi::host::ReplyMessageContext reply_msg, |
| 464 ProvidedFilesystemInfo filesystem_info, |
| 465 base::File::Error err) { |
| 466 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 467 |
| 468 // If an error occured or we cannot initialize the shared memory |
| 469 if ( err != base::File::FILE_OK || |
| 470 !InitializeMemoryBuffer()) { |
| 471 reply_msg.params.set_result(PP_ERROR_FAILED); |
| 472 host_->SendReply( |
| 473 reply_msg, |
| 474 PpapiPluginMsg_FilesystemProvider_MountReply() |
| 475 ); |
| 476 // Undo the registration |
| 477 if (err==base::File::FILE_OK) { |
| 478 BrowserThread::PostTask( |
| 479 BrowserThread::UI, |
| 480 FROM_HERE, |
| 481 base::Bind( |
| 482 base::IgnoreResult( |
| 483 &PepperFilesystemProviderBackendChromeOS:: |
| 484 UnregisterFilesystemOnUI), |
| 485 filesystem_info |
| 486 ) |
| 487 ); |
| 488 } |
| 489 return; |
| 490 } |
| 491 |
| 492 RegisterFilesystemListenedOperations(); |
| 493 mounted_ = true; |
| 494 filesystem_info_.writable = filesystem_info.writable; |
| 495 filesystem_info_.display_name = filesystem_info.display_name; |
| 496 filesystem_info_.filesystem_id = filesystem_info.filesystem_id; |
| 497 filesystem_info_.opened_files_limit = filesystem_info.opened_files_limit; |
| 498 |
| 499 |
| 500 reply_msg.params.set_result(PP_OK); |
| 501 host_->SendReply( |
| 502 reply_msg, |
| 503 PpapiPluginMsg_FilesystemProvider_MountReply() |
| 504 ); |
| 505 } |
| 506 |
| 507 //static |
| 508 // Responsible with removal of the filesystem backend |
| 509 base::File::Error PepperFilesystemProviderBackendChromeOS:: |
| 510 UnregisterFilesystemOnUI( |
| 511 ProvidedFilesystemInfo filesystem_info) { |
| 512 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 513 |
| 514 PluginService *fs_service = PluginService::Get( |
| 515 ProfileManager::GetActiveUserProfile()); |
| 516 DCHECK(fs_service); |
| 517 |
| 518 base::File::Error err = fs_service->UnmountFileSystem( |
| 519 filesystem_info.plugin_name, |
| 520 filesystem_info.filesystem_id, |
| 521 chromeos::file_system_provider::PluginService::UNMOUNT_REASON_USER ); |
| 522 |
| 523 return err; |
| 524 } |
| 525 |
| 526 // Sends feedback to the plugin |
| 527 // and resets state |
| 528 void PepperFilesystemProviderBackendChromeOS::UnmountReplyOnIO( |
| 529 ppapi::host::ReplyMessageContext reply_msg, base::File::Error err) { |
| 530 |
| 531 reply_msg.params.set_result(PP_OK); |
| 532 // Unregister all events |
| 533 UnregisterFilesystemListenedOperations(); |
| 534 |
| 535 mounted_ = false; |
| 536 // Send result to the plugin |
| 537 host_->SendReply( |
| 538 reply_msg, |
| 539 PpapiPluginMsg_FilesystemProvider_UnmountReply() |
| 540 ); |
| 541 } |
| 542 |
| 543 void PepperFilesystemProviderBackendChromeOS::OnDispatchOperationRequest( |
| 544 RequestType operation_type, scoped_ptr<base::ListValue> request) { |
| 545 if ( operation_type==WRITE_FILE ) { |
| 546 // Handle write to filesystem |
| 547 // Put the chunk into the shared memory buffer or cache it |
| 548 // if channel is not free |
| 549 // TODO(sabin): Send error back to backend if this fails |
| 550 write_channel_controller_->EnqueueRequest(request.Pass()); |
| 551 } else { |
| 552 //TODO(sabin): Remove this when done testing |
| 553 if(operation_type==OPEN_FILE) |
| 554 time_stamp_=std::chrono::system_clock::now(); |
| 555 else if(operation_type==CLOSE_FILE) { |
| 556 std::chrono::duration<double> elapsed_seconds = |
| 557 std::chrono::system_clock::now()-time_stamp_; |
| 558 LOG(ERROR) <<"Read/Write operation time: "<< elapsed_seconds.count()<< |
| 559 " seconds"; |
| 560 } |
| 561 host_->SendUnsolicitedReply( |
| 562 resource_, |
| 563 PpapiPluginMsg_FilesystemProvider_OperationRequest( |
| 564 RequestTypeToOperationType(operation_type), |
| 565 *request) |
| 566 ); |
| 567 } |
| 568 } |
| 569 |
| 570 // Transforms messages that are received from |
| 571 // the plugin in response of filesystem operations and sends |
| 572 // them back to the filesystem backend. |
| 573 int32_t PepperFilesystemProviderBackendChromeOS::OnSuccessResponse( |
| 574 int operation, |
| 575 const ProvidedFilesystemInfo& filesystem_info, |
| 576 scoped_ptr<base::ListValue> response ) { |
| 577 |
| 578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 579 PluginService *fs_service = PluginService::Get( |
| 580 ProfileManager::GetActiveUserProfile()); |
| 581 DCHECK(fs_service); |
| 582 |
| 583 ProvidedFileSystemAdapter* fs_backend = |
| 584 fs_service->GetProvidedFileSystemAdapter( |
| 585 filesystem_info.plugin_name, |
| 586 filesystem_info.filesystem_id); |
| 587 |
| 588 if (fs_backend==nullptr) |
| 589 return PP_ERROR_FAILED; |
| 590 fs_backend->PushSuccessResponse( PP_OperationToRequestType(operation), |
| 591 response.Pass()); |
| 592 |
| 593 return PP_OK; |
| 594 } |
| 595 |
| 596 int32_t PepperFilesystemProviderBackendChromeOS::OnErrorResponse( |
| 597 const ProvidedFilesystemInfo& filesystem_info, |
| 598 scoped_ptr<base::ListValue> response) { |
| 599 |
| 600 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 601 |
| 602 PluginService *fs_service = PluginService::Get( |
| 603 ProfileManager::GetActiveUserProfile()); |
| 604 DCHECK(fs_service); |
| 605 |
| 606 ProvidedFileSystemAdapter* fs_backend = |
| 607 fs_service->GetProvidedFileSystemAdapter( |
| 608 filesystem_info.plugin_name, |
| 609 filesystem_info.filesystem_id); |
| 610 if(fs_backend==nullptr) |
| 611 return PP_ERROR_FAILED; |
| 612 fs_backend->PushErrorResponse(response.Pass()); |
| 613 return PP_OK; |
| 614 } |
| 615 |
| 616 bool PepperFilesystemProviderBackendChromeOS::FlushRequest( |
| 617 scoped_ptr<base::ListValue> request) { |
| 618 if(!request.get()) |
| 619 return false; |
| 620 |
| 621 if(!AddFromMessageToSharedMemory(*request)) |
| 622 return false; |
| 623 |
| 624 host_->SendUnsolicitedReply( |
| 625 resource_, |
| 626 PpapiPluginMsg_FilesystemProvider_OperationRequest( |
| 627 PP_OperationType_WRITEFILE, |
| 628 *request)); |
| 629 return true; |
| 630 } |
| 631 bool PepperFilesystemProviderBackendChromeOS::InitializeMemoryBuffer() { |
| 632 // Already initialized |
| 633 if(read_write_buffer_.get()) |
| 634 return true; |
| 635 scoped_ptr<base::SharedMemory> buffer( new base::SharedMemory ); |
| 636 size_t size = kReaderBufferSize + kWriterBufferSize; |
| 637 if (!buffer.get() || |
| 638 !buffer->CreateAndMapAnonymous(size)) |
| 639 return false; |
| 640 read_write_buffer_=make_scoped_ptr(new ShmBuffer(size, buffer.Pass())); |
| 641 if(!read_write_buffer_.get()) |
| 642 return false; |
| 643 using ppapi::proxy::SerializedHandle; |
| 644 std::vector<SerializedHandle> handles; |
| 645 handles.push_back( |
| 646 SerializedHandle(read_write_buffer_->shm->handle(), size )); |
| 647 // Send a message to the plugin with the shared mem handle |
| 648 host_->SendUnsolicitedReplyWithHandles( |
| 649 resource_, |
| 650 PpapiPluginMsg_FilesystemProvider_Buffers( |
| 651 kReaderBufferSize, |
| 652 kWriterBufferSize), |
| 653 handles |
| 654 ); |
| 655 return true; |
| 656 } |
| 657 bool PepperFilesystemProviderBackendChromeOS::AddFromSharedMemoryToMessage( |
| 658 base::ListValue& message) { |
| 659 DCHECK(read_write_buffer_.get()); |
| 660 double out = 0; |
| 661 if(!message.GetDouble(2,&out)) |
| 662 return false; |
| 663 size_t out_size = out; |
| 664 if(out_size>kReaderBufferSize) |
| 665 return false; |
| 666 |
| 667 // Replace the size with the actual data |
| 668 bool status = message.Set(2, base::BinaryValue::CreateWithCopiedBuffer( |
| 669 (const char*)read_write_buffer_->shm->memory(), out_size)); |
| 670 SendReadAck(); |
| 671 return status; |
| 672 } |
| 673 bool PepperFilesystemProviderBackendChromeOS::AddFromMessageToSharedMemory( |
| 674 base::ListValue& message) { |
| 675 if( !read_write_buffer_.get() ) |
| 676 return false; |
| 677 |
| 678 base::Value *dict_value = nullptr; |
| 679 if(!message.Get(0,&dict_value)) |
| 680 return false; |
| 681 |
| 682 base::DictionaryValue* dict = |
| 683 static_cast<base::DictionaryValue*>(dict_value); |
| 684 const base::BinaryValue* binary_value = NULL; |
| 685 if (!dict->GetBinary("data", &binary_value)) |
| 686 return false; |
| 687 // This can be '0' |
| 688 size_t binary_size =binary_value->GetSize(); |
| 689 // Skip the read buffer and copy to shared mem the buffer into |
| 690 // the write portion of the buffer |
| 691 if(binary_size>kWriterBufferSize) |
| 692 return false; |
| 693 memcpy( (char*)read_write_buffer_->shm->memory()+kReaderBufferSize, |
| 694 binary_value->GetBuffer(), |
| 695 binary_size); |
| 696 dict->Remove( "data", nullptr ); |
| 697 dict->SetDouble( "size",binary_size); |
| 698 return true; |
| 699 } |
| 700 bool PepperFilesystemProviderBackendChromeOS::PreprocessMessage( |
| 701 base::ListValue& message, |
| 702 bool& message_status, |
| 703 int& operation_type) { |
| 704 // Remove the custom "header" from the response |
| 705 scoped_ptr<base::Value> operation_value = nullptr; |
| 706 if (!message.Remove(0,&operation_value)) |
| 707 return false; |
| 708 if (!operation_value->GetAsInteger(&operation_type)) |
| 709 return false; |
| 710 // Get the status of the operation |
| 711 scoped_ptr<base::Value> status_value=nullptr; |
| 712 if (!message.Remove(0,&status_value)) |
| 713 return false; |
| 714 if (!status_value->GetAsBoolean(&message_status)) |
| 715 return false; |
| 716 switch (operation_type) { |
| 717 case PP_OperationType_READFILE: |
| 718 if (!AddFromSharedMemoryToMessage(message)) |
| 719 return false; |
| 720 break; |
| 721 case PP_OperationType_UNMOUNT: |
| 722 if ( message_status ) |
| 723 mounted_ = false; |
| 724 break; |
| 725 default: |
| 726 break; |
| 727 } |
| 728 return true; |
| 729 } |
| 730 |
| 731 void PepperFilesystemProviderBackendChromeOS::SendReadAck() { |
| 732 // ACK the receipt and let the plugin know that if it has more |
| 733 // requests it can send them |
| 734 if (host_) |
| 735 host_->SendUnsolicitedReply(resource_, |
| 736 PpapiPluginMsg_FilesystemProvider_ReadAck()); |
| 737 } |
| 738 |
| 739 namespace filesystem_provider_internal { |
| 740 scoped_ptr<MountOperationTranslator> |
| 741 MountOperationTranslator::PopulateFromResponse( |
| 742 const base::ListValue& request) { |
| 743 const base::Value *dict_value = nullptr; |
| 744 if(!request.Get(0,&dict_value)) |
| 745 return scoped_ptr<MountOperationTranslator>(); |
| 746 |
| 747 const base::DictionaryValue* dict = |
| 748 static_cast<const base::DictionaryValue*>(dict_value); |
| 749 |
| 750 scoped_ptr< MountOperationTranslator > out(new MountOperationTranslator); |
| 751 |
| 752 const base::Value* data_value = nullptr; |
| 753 if (!dict->GetWithoutPathExpansion("fileSystemId", &data_value) || |
| 754 !data_value->IsType(base::Value::TYPE_STRING)) |
| 755 return scoped_ptr<MountOperationTranslator>(); |
| 756 if (!data_value->GetAsString(&out->file_system_id)) |
| 757 return scoped_ptr<MountOperationTranslator>(); |
| 758 if (!dict->GetWithoutPathExpansion("displayName", &data_value) || |
| 759 !data_value->IsType(base::Value::TYPE_STRING)) |
| 760 return scoped_ptr<MountOperationTranslator>(); |
| 761 if (!data_value->GetAsString(&out->display_name)) |
| 762 return scoped_ptr<MountOperationTranslator>(); |
| 763 if (!dict->GetWithoutPathExpansion("writable", &data_value) || |
| 764 !data_value->IsType(base::Value::TYPE_BOOLEAN)) |
| 765 return scoped_ptr<MountOperationTranslator>(); |
| 766 if (!data_value->GetAsBoolean(&out->writable)) |
| 767 return scoped_ptr<MountOperationTranslator>(); |
| 768 |
| 769 if (!dict->GetWithoutPathExpansion("openedFilesLimit", &data_value) || |
| 770 !data_value->IsType(base::Value::TYPE_INTEGER)) |
| 771 return scoped_ptr<MountOperationTranslator>(); |
| 772 if (!data_value->GetAsInteger(&out->opened_files_limit)) |
| 773 return scoped_ptr<MountOperationTranslator>(); |
| 774 |
| 775 return out.Pass(); |
| 776 } |
| 777 } // namespace filesystem_provider_internal |
| 778 } // namespace content |
| 779 |
OLD | NEW |