Chromium Code Reviews| Index: ppapi/proxy/ppb_flash_proxy.cc |
| diff --git a/ppapi/proxy/ppb_flash_proxy.cc b/ppapi/proxy/ppb_flash_proxy.cc |
| index 9c91830f36604a6b11ac88cfe56d7995224d1b2a..6f37b7067812c9045e5c86787e5ff3be7f52aa93 100644 |
| --- a/ppapi/proxy/ppb_flash_proxy.cc |
| +++ b/ppapi/proxy/ppb_flash_proxy.cc |
| @@ -35,6 +35,332 @@ using ppapi::thunk::EnterInstanceNoLock; |
| namespace ppapi { |
| namespace proxy { |
| +namespace { |
| + |
| +IPC::PlatformFileForTransit PlatformFileToPlatformFileForTransit( |
|
brettw
2012/04/24 22:48:47
This stuff was just moved from the file_proxy.cc
|
| + Dispatcher* dispatcher, |
| + int32_t* error, |
| + base::PlatformFile file) { |
| + if (*error != PP_OK) |
| + return IPC::InvalidPlatformFileForTransit(); |
| + IPC::PlatformFileForTransit out_handle = |
| + dispatcher->ShareHandleWithRemote(file, true); |
| + if (out_handle == IPC::InvalidPlatformFileForTransit()) |
| + *error = PP_ERROR_NOACCESS; |
| + return out_handle; |
| +} |
| + |
| +// ModuleLocalThreadAdapter ---------------------------------------------------- |
| +// TODO(yzshen): Refactor to use IPC::SyncMessageFilter. |
| +class ModuleLocalThreadAdapter |
| + : public base::RefCountedThreadSafe<ModuleLocalThreadAdapter> { |
|
yzshen1
2012/04/25 20:50:47
Please include .h for things such as RefCountedThr
|
| + class Filter; |
| + public: |
| + ModuleLocalThreadAdapter(); |
| + |
| + void AddInstanceRouting(PP_Instance instance, Dispatcher* dispatcher); |
| + void ClearInstanceRouting(PP_Instance instance); |
| + void ClearFilter(Dispatcher* dispatcher, Filter* filter); |
| + |
| + bool OnModuleLocalMessageReceived(const IPC::Message& msg); |
| + |
| + // Called on the I/O thread when the channel is being destroyed and the |
| + // given message will never be issued a reply. |
| + void OnModuleLocalMessageFailed(int message_id); |
| + |
| + bool Send(PP_Instance instance, IPC::Message* msg); |
| + |
| + private: |
| + class Filter : public IPC::ChannelProxy::MessageFilter { |
| + public: |
| + explicit Filter(Dispatcher* dispatcher); |
| + ~Filter(); |
| + |
| + void Send(IPC::Message* msg); |
| + |
| + virtual void OnFilterAdded(IPC::Channel* channel); |
| + virtual void OnFilterRemoved(); |
| + virtual bool OnMessageReceived(const IPC::Message& message); |
| + |
| + private: |
| + // DO NOT DEREFERENCE! This is used only for tracking. |
| + Dispatcher* dispatcher_; |
| + |
| + IPC::Channel* channel_; |
| + |
| + // Holds the IPC messages that were sent before the channel was connected. |
| + // These will be sent ASAP. |
| + std::vector<IPC::Message*> pre_connect_pending_messages_; |
| + |
| + // Holds the IDs of the sync messages we're currently waiting on for this |
| + // channel. This tracking allows us to cancel those requests if the |
| + // remote process crashes and we're cleaning up this filter (without just |
| + // deadlocking the waiting thread(s). |
| + std::set<int> pending_requests_for_filter_; |
| + }; |
| + |
| + void SendFromIOThread(Dispatcher* dispatcher, IPC::Message* msg); |
| + |
| + // Internal version of OnModuleLocalMessageFailed which assumes the lock |
| + // is already held. |
| + void OnModuleLocalMessageFailedLocked(int message_id); |
| + |
| + base::Lock lock_; |
| + |
| + scoped_refptr<base::MessageLoopProxy> main_thread_; |
| + |
| + // Will be NULL before an instance routing is added. |
| + scoped_refptr<base::MessageLoopProxy> io_thread_; |
| + |
| + typedef std::map<PP_Instance, Dispatcher*> InstanceToDispatcher; |
| + InstanceToDispatcher instance_to_dispatcher_; |
| + |
| + // The filters are owned by the channel. |
| + typedef std::map<Dispatcher*, Filter*> DispatcherToFilter; |
| + DispatcherToFilter dispatcher_to_filter_; |
| + |
| + // Tracks all messages with currently waiting threads. This does not own |
| + // the pointer, the pointer lifetime is managed by Send(). |
| + typedef std::map<int, IPC::PendingSyncMsg*> SyncRequestMap; |
| + SyncRequestMap pending_sync_requests_; |
| +}; |
| + |
| +ModuleLocalThreadAdapter* g_module_local_thread_adapter = NULL; |
| + |
| +ModuleLocalThreadAdapter::Filter::Filter(Dispatcher* dispatcher) |
| + : dispatcher_(dispatcher), channel_(NULL) { |
| +} |
| + |
| +ModuleLocalThreadAdapter::Filter::~Filter() { |
| +} |
| + |
| +void ModuleLocalThreadAdapter::Filter::Send(IPC::Message* msg) { |
| + if (channel_) { |
| + int message_id = IPC::SyncMessage::GetMessageId(*msg); |
| + if (channel_->Send(msg)) |
| + pending_requests_for_filter_.insert(message_id); |
| + else // Message lost, notify adapter so it can unblock. |
| + g_module_local_thread_adapter->OnModuleLocalMessageFailed(message_id); |
| + } else { |
| + // No channel, save this message for when it's connected. |
| + pre_connect_pending_messages_.push_back(msg); |
| + } |
| +} |
| + |
| +void ModuleLocalThreadAdapter::Filter::OnFilterAdded(IPC::Channel* channel) { |
| + DCHECK(!channel_); |
| + channel_ = channel; |
| + |
| + // Now that we have a channel, process all pending messages. |
| + for (size_t i = 0; i < pre_connect_pending_messages_.size(); i++) |
| + Send(pre_connect_pending_messages_[i]); |
| + pre_connect_pending_messages_.clear(); |
| +} |
| + |
| +void ModuleLocalThreadAdapter::Filter::OnFilterRemoved() { |
| + DCHECK(channel_); |
| + channel_ = NULL; |
| + g_module_local_thread_adapter->ClearFilter(dispatcher_, this); |
| + |
| + for (std::set<int>::iterator i = pending_requests_for_filter_.begin(); |
| + i != pending_requests_for_filter_.end(); ++i) { |
| + g_module_local_thread_adapter->OnModuleLocalMessageFailed(*i); |
| + } |
| +} |
| + |
| +bool ModuleLocalThreadAdapter::Filter::OnMessageReceived( |
| + const IPC::Message& message) { |
| + if (!message.is_reply() || |
| + message.routing_id() != API_ID_PPB_FLASH) |
| + return false; |
| + |
| + if (g_module_local_thread_adapter->OnModuleLocalMessageReceived(message)) { |
| + // The message was consumed, this means we can remove the message ID from |
| + // the list of messages this channel is waiting on. |
| + pending_requests_for_filter_.erase(IPC::SyncMessage::GetMessageId(message)); |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +ModuleLocalThreadAdapter::ModuleLocalThreadAdapter() |
| + : main_thread_(base::MessageLoopProxy::current()) { |
| +} |
| + |
| +void ModuleLocalThreadAdapter::AddInstanceRouting(PP_Instance instance, |
| + Dispatcher* dispatcher) { |
| + base::AutoLock lock(lock_); |
| + |
| + // Now that we've had contact with a dispatcher, we can set up the IO thread. |
| + DCHECK(main_thread_->BelongsToCurrentThread()); |
| + if (!io_thread_.get()) |
| + io_thread_ = dispatcher->GetIPCMessageLoop(); |
| + |
| + // Set up the instance -> dispatcher routing. |
| + DCHECK(instance_to_dispatcher_.find(instance) == |
| + instance_to_dispatcher_.end()); |
| + instance_to_dispatcher_[instance] = dispatcher; |
| + |
| + DispatcherToFilter::iterator found_filter = |
| + dispatcher_to_filter_.find(dispatcher); |
| + if (found_filter == dispatcher_to_filter_.end()) { |
| + // Need to set up a filter for this dispatcher to intercept the messages. |
| + Filter* filter = new Filter(dispatcher); |
| + dispatcher_to_filter_[dispatcher] = filter; |
| + dispatcher->AddIOThreadMessageFilter(filter); |
| + } |
| +} |
| + |
| +void ModuleLocalThreadAdapter::ClearInstanceRouting(PP_Instance instance) { |
| + // The dispatcher->filter mapping is cleaned up by ClearFilter which is |
| + // initiated by the channel. |
| + instance_to_dispatcher_.erase(instance); |
| +} |
| + |
| +void ModuleLocalThreadAdapter::ClearFilter(Dispatcher* dispatcher, |
| + Filter* filter) { |
| + // DANGER! Don't dereference the dispatcher, it's just used to identify |
| + // which filter to remove. The dispatcher may not even exist any more. |
| + // |
| + // Since the dispatcher may be gone, there's a potential for ambiguity if |
| + // another one is created on the main thread before this code runs on the |
| + // I/O thread. So we check that the filter matches to avoid this rare case. |
| + base::AutoLock lock(lock_); |
| + if (dispatcher_to_filter_[dispatcher] == filter) |
| + dispatcher_to_filter_.erase(dispatcher); |
| +} |
| + |
| +bool ModuleLocalThreadAdapter::OnModuleLocalMessageReceived( |
| + const IPC::Message& msg) { |
| + base::AutoLock lock(lock_); |
| + |
| + int message_id = IPC::SyncMessage::GetMessageId(msg); |
| + SyncRequestMap::iterator found = pending_sync_requests_.find(message_id); |
| + if (found == pending_sync_requests_.end()) { |
| + // Not waiting for this event. This will happen for sync messages to the |
| + // main thread which use the "regular" sync channel code path. |
| + return false; |
| + } |
| + |
| + IPC::PendingSyncMsg& info = *found->second; |
| + |
| + if (!msg.is_reply_error()) |
| + info.deserializer->SerializeOutputParameters(msg); |
| + info.done_event->Signal(); |
| + return true; |
| +} |
| + |
| +void ModuleLocalThreadAdapter::OnModuleLocalMessageFailed(int message_id) { |
| + base::AutoLock lock(lock_); |
| + OnModuleLocalMessageFailedLocked(message_id); |
| +} |
| + |
| +bool ModuleLocalThreadAdapter::Send(PP_Instance instance, IPC::Message* msg) { |
| + // Compute the dispatcher corresponding to this message. |
| + Dispatcher* dispatcher = NULL; |
| + { |
| + base::AutoLock lock(lock_); |
| + InstanceToDispatcher::iterator found = |
| + instance_to_dispatcher_.find(instance); |
| + if (found == instance_to_dispatcher_.end()) { |
| + NOTREACHED(); |
| + delete msg; |
| + return false; |
| + } |
| + dispatcher = found->second; |
| + } |
| + |
| + if (main_thread_->BelongsToCurrentThread()) { |
| + // Easy case: We're on the same thread as the dispatcher, so we don't need |
| + // a lock to access it, and we can just use the normal sync channel stuff |
| + // to handle the message. Actually, we MUST use the normal sync channel |
| + // stuff since there may be incoming sync messages that need processing. |
| + // The code below doesn't handle any nested message loops. |
| + return dispatcher->Send(msg); |
| + } |
| + |
| + // Background thread case |
| + // ---------------------- |
| + // 1. Generate tracking info, stick in pending_sync_messages_map. |
| + // 2. Kick off the request. This is done on the I/O thread. |
| + // 3. Filter on the I/O thread notices reply, writes the reply data and |
| + // signals the event. We block on the event while this is happening. |
| + // 4. Remove tracking info. |
| + |
| + // Generate the tracking info. and copied |
| + IPC::SyncMessage* sync_msg = static_cast<IPC::SyncMessage*>(msg); |
| + int message_id = IPC::SyncMessage::GetMessageId(*sync_msg); |
| + base::WaitableEvent event(true, false); |
| + scoped_ptr<IPC::MessageReplyDeserializer> deserializer( |
| + sync_msg->GetReplyDeserializer()); // We own this pointer once retrieved. |
| + IPC::PendingSyncMsg info(message_id, deserializer.get(), &event); |
| + |
| + // Add the tracking information to our map. |
| + { |
| + base::AutoLock lock(lock_); |
| + pending_sync_requests_[message_id] = &info; |
| + } |
| + |
| + // This is a bit dangerous. We use the dispatcher pointer as the routing |
| + // ID for this message. While we don't dereference it, there is an |
| + // exceedingly remote possibility that while this is going to the background |
| + // thread the connection will be shut down and a new one will be created with |
| + // a dispatcher at the same address. It could potentially get sent to a |
| + // random place, but it should actually still work (since the Flash file |
| + // operations are global). |
| + io_thread_->PostTask(FROM_HERE, |
| + base::Bind(&ModuleLocalThreadAdapter::SendFromIOThread, this, |
| + dispatcher, msg)); |
| + |
| + // Now we block the current thread waiting for the reply. |
| + event.Wait(); |
| + |
| + { |
| + // Clear our tracking info for this message now that we're done. |
| + base::AutoLock lock(lock_); |
| + DCHECK(pending_sync_requests_.find(message_id) != |
| + pending_sync_requests_.end()); |
| + pending_sync_requests_.erase(message_id); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +void ModuleLocalThreadAdapter::SendFromIOThread(Dispatcher* dispatcher, |
| + IPC::Message* msg) { |
| + // DO NOT DEREFERENCE DISPATCHER. Used as a lookup only. |
| + base::AutoLock lock(lock_); |
| + DispatcherToFilter::iterator found = dispatcher_to_filter_.find(dispatcher); |
| + |
| + // The dispatcher could have been destroyed by the time we got here since |
| + // we're on another thread. Need to unblock the caller. |
| + if (found == dispatcher_to_filter_.end()) { |
| + OnModuleLocalMessageFailedLocked(IPC::SyncMessage::GetMessageId(*msg)); |
| + delete msg; |
| + return; |
| + } |
| + |
| + // Takes ownership of pointer. |
| + found->second->Send(msg); |
| +} |
| + |
| +void ModuleLocalThreadAdapter::OnModuleLocalMessageFailedLocked( |
| + int message_id) { |
| + lock_.AssertAcquired(); |
| + |
| + // Unblock the thread waiting for the message that will never come. |
| + SyncRequestMap::iterator found = pending_sync_requests_.find(message_id); |
| + if (found == pending_sync_requests_.end()) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + found->second->done_event->Signal(); |
| +} |
| + |
| +} // namespace |
| + |
| +// ----------------------------------------------------------------------------- |
| + |
| PPB_Flash_Proxy::PPB_Flash_Proxy(Dispatcher* dispatcher) |
| : InterfaceProxy(dispatcher) { |
| } |
| @@ -75,6 +401,22 @@ bool PPB_Flash_Proxy::OnMessageReceived(const IPC::Message& msg) { |
| OnHostMsgReadClipboardData) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_WriteClipboardData, |
| OnHostMsgWriteClipboardData) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_OpenFile, |
| + OnHostMsgOpenFile) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_RenameFile, |
| + OnHostMsgRenameFile) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_DeleteFileOrDir, |
| + OnHostMsgDeleteFileOrDir) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_CreateDir, |
| + OnHostMsgCreateDir) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_QueryFile, |
| + OnHostMsgQueryFile) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_GetDirContents, |
| + OnHostMsgGetDirContents) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_OpenFileRef, |
| + OnHostMsgOpenFileRef) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_QueryFileRef, |
| + OnHostMsgQueryFileRef) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| // TODO(brettw) handle bad messages! |
| @@ -268,6 +610,164 @@ int32_t PPB_Flash_Proxy::WriteClipboardData( |
| return PP_OK; |
| } |
| +bool PPB_Flash_Proxy::CreateThreadAdapterForInstance(PP_Instance instance) { |
| + if (!g_module_local_thread_adapter) { |
| + g_module_local_thread_adapter = new ModuleLocalThreadAdapter(); |
| + g_module_local_thread_adapter->AddRef(); // Leaked, this object is global. |
| + } |
| + |
| + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); |
| + if (!dispatcher) { |
| + NOTREACHED(); |
| + return false; |
| + } |
| + g_module_local_thread_adapter->AddInstanceRouting(instance, dispatcher); |
| + return true; |
| +} |
| + |
| +void PPB_Flash_Proxy::ClearThreadAdapterForInstance(PP_Instance instance) { |
| + if (g_module_local_thread_adapter) |
| + g_module_local_thread_adapter->ClearInstanceRouting(instance); |
| +} |
| + |
| +int32_t PPB_Flash_Proxy::OpenFile(PP_Instance instance, |
| + const char* path, |
| + int32_t mode, |
| + PP_FileHandle* file) { |
| + if (!g_module_local_thread_adapter) |
| + return PP_ERROR_FAILED; |
| + |
| + int32_t result = PP_ERROR_FAILED; |
| + IPC::PlatformFileForTransit transit; |
| + g_module_local_thread_adapter->Send(instance, |
| + new PpapiHostMsg_PPBFlash_OpenFile( |
| + API_ID_PPB_FLASH, instance, path, mode, &transit, &result)); |
| + *file = IPC::PlatformFileForTransitToPlatformFile(transit); |
| + return result; |
| +} |
| + |
| +int32_t PPB_Flash_Proxy::RenameFile(PP_Instance instance, |
| + const char* path_from, |
| + const char* path_to) { |
| + if (!g_module_local_thread_adapter) |
| + return PP_ERROR_FAILED; |
| + |
| + int32_t result = PP_ERROR_FAILED; |
| + g_module_local_thread_adapter->Send(instance, |
| + new PpapiHostMsg_PPBFlash_RenameFile( |
| + API_ID_PPB_FLASH, instance, path_from, path_to, &result)); |
| + return result; |
| +} |
| + |
| +int32_t PPB_Flash_Proxy::DeleteFileOrDir(PP_Instance instance, |
| + const char* path, |
| + PP_Bool recursive) { |
| + if (!g_module_local_thread_adapter) |
| + return PP_ERROR_FAILED; |
| + |
| + int32_t result = PP_ERROR_FAILED; |
| + g_module_local_thread_adapter->Send(instance, |
| + new PpapiHostMsg_PPBFlash_DeleteFileOrDir( |
| + API_ID_PPB_FLASH, instance, path, recursive, &result)); |
| + return result; |
| +} |
| + |
| +int32_t PPB_Flash_Proxy::CreateDir(PP_Instance instance, const char* path) { |
| + if (!g_module_local_thread_adapter) |
| + return PP_ERROR_FAILED; |
| + |
| + int32_t result = PP_ERROR_FAILED; |
| + g_module_local_thread_adapter->Send(instance, |
| + new PpapiHostMsg_PPBFlash_CreateDir( |
| + API_ID_PPB_FLASH, instance, path, &result)); |
| + return result; |
| +} |
| + |
| +int32_t PPB_Flash_Proxy::QueryFile(PP_Instance instance, |
| + const char* path, |
| + PP_FileInfo* info) { |
| + if (!g_module_local_thread_adapter) |
| + return PP_ERROR_FAILED; |
| + |
| + int32_t result = PP_ERROR_FAILED; |
| + g_module_local_thread_adapter->Send(instance, |
| + new PpapiHostMsg_PPBFlash_QueryFile( |
| + API_ID_PPB_FLASH, instance, path, info, &result)); |
| + return result; |
| +} |
| + |
| +int32_t PPB_Flash_Proxy::GetDirContents(PP_Instance instance, |
| + const char* path, |
| + PP_DirContents_Dev** contents) { |
| + if (!g_module_local_thread_adapter) |
| + return PP_ERROR_FAILED; |
| + |
| + int32_t result = PP_ERROR_FAILED; |
| + std::vector<SerializedDirEntry> entries; |
| + g_module_local_thread_adapter->Send(instance, |
| + new PpapiHostMsg_PPBFlash_GetDirContents( |
| + API_ID_PPB_FLASH, instance, path, &entries, &result)); |
| + |
| + if (result != PP_OK) |
| + return result; |
| + |
| + // Copy the serialized dir entries to the output struct. |
| + *contents = new PP_DirContents_Dev; |
| + (*contents)->count = static_cast<int32_t>(entries.size()); |
| + (*contents)->entries = new PP_DirEntry_Dev[entries.size()]; |
| + for (size_t i = 0; i < entries.size(); i++) { |
| + const SerializedDirEntry& source = entries[i]; |
| + PP_DirEntry_Dev* dest = &(*contents)->entries[i]; |
| + |
| + char* name_copy = new char[source.name.size() + 1]; |
| + memcpy(name_copy, source.name.c_str(), source.name.size() + 1); |
| + dest->name = name_copy; |
| + dest->is_dir = PP_FromBool(source.is_dir); |
| + } |
| + |
| + return result; |
| +} |
| + |
| +int32_t PPB_Flash_Proxy::OpenFileRef(PP_Instance instance, |
| + PP_Resource file_ref_id, |
| + int32_t mode, |
| + PP_FileHandle* file) { |
| + Resource* file_ref = |
| + PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_ref_id); |
|
yzshen1
2012/04/25 20:50:47
Can we use EnterResourceNoLock? (And also line 757
|
| + if (!file_ref) |
| + return PP_ERROR_BADRESOURCE; |
| + |
| + PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(file_ref); |
|
yzshen1
2012/04/25 20:50:47
Can we use dispatcher() here? (And also line 761.)
|
| + if (!dispatcher) |
| + return PP_ERROR_BADARGUMENT; |
| + |
| + int32_t result = PP_ERROR_FAILED; |
| + IPC::PlatformFileForTransit transit; |
| + dispatcher->Send(new PpapiHostMsg_PPBFlash_OpenFileRef( |
| + API_ID_PPB_FLASH, instance, file_ref->host_resource(), mode, &transit, |
| + &result)); |
| + *file = IPC::PlatformFileForTransitToPlatformFile(transit); |
| + return result; |
| +} |
| + |
| +int32_t PPB_Flash_Proxy::QueryFileRef(PP_Instance instance, |
| + PP_Resource file_ref_id, |
| + PP_FileInfo* info) { |
| + Resource* file_ref = |
| + PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_ref_id); |
| + if (!file_ref) |
| + return PP_ERROR_BADRESOURCE; |
| + |
| + PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(file_ref); |
| + if (!dispatcher) |
| + return PP_ERROR_BADARGUMENT; |
| + |
| + int32_t result = PP_ERROR_FAILED; |
| + dispatcher->Send(new PpapiHostMsg_PPBFlash_QueryFileRef( |
| + API_ID_PPB_FLASH, instance, file_ref->host_resource(), info, &result)); |
| + return result; |
| +} |
| + |
| PP_Bool PPB_Flash_Proxy::FlashIsFullscreen(PP_Instance instance) { |
| InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())-> |
| GetInstanceData(instance); |
| @@ -500,5 +1000,121 @@ void PPB_Flash_Proxy::OnHostMsgWriteClipboardData( |
| } |
| } |
| +void PPB_Flash_Proxy::OnHostMsgOpenFile( |
| + PP_Instance instance, |
| + const std::string& path, |
| + int32_t mode, |
| + IPC::PlatformFileForTransit* file_handle, |
| + int32_t* result) { |
| + EnterInstanceNoLock enter(instance); |
| + if (enter.succeeded()) { |
|
yzshen1
2012/04/25 20:50:47
Please set |result| if enter.failed() here and som
|
| + base::PlatformFile file; |
| + *result = enter.functions()->GetFlashAPI()->OpenFile( |
| + instance, path.c_str(), mode, &file); |
| + *file_handle = PlatformFileToPlatformFileForTransit( |
| + dispatcher(), result, file); |
| + } |
| +} |
| + |
| +void PPB_Flash_Proxy::OnHostMsgRenameFile(PP_Instance instance, |
| + const std::string& from_path, |
| + const std::string& to_path, |
| + int32_t* result) { |
| + EnterInstanceNoLock enter(instance); |
| + if (enter.succeeded()) { |
| + *result = enter.functions()->GetFlashAPI()->RenameFile( |
| + instance, from_path.c_str(), to_path.c_str()); |
| + } |
| +} |
| + |
| +void PPB_Flash_Proxy::OnHostMsgDeleteFileOrDir(PP_Instance instance, |
| + const std::string& path, |
| + PP_Bool recursive, |
| + int32_t* result) { |
| + EnterInstanceNoLock enter(instance); |
| + if (enter.succeeded()) { |
| + *result = enter.functions()->GetFlashAPI()->DeleteFileOrDir( |
| + instance, path.c_str(), recursive); |
| + } |
| +} |
| + |
| +void PPB_Flash_Proxy::OnHostMsgCreateDir(PP_Instance instance, |
| + const std::string& path, |
| + int32_t* result) { |
| + EnterInstanceNoLock enter(instance); |
| + if (enter.succeeded()) { |
| + *result = enter.functions()->GetFlashAPI()->CreateDir( |
| + instance, path.c_str()); |
| + } |
| +} |
| + |
| +void PPB_Flash_Proxy::OnHostMsgQueryFile(PP_Instance instance, |
| + const std::string& path, |
| + PP_FileInfo* info, |
| + int32_t* result) { |
| + EnterInstanceNoLock enter(instance); |
| + if (enter.succeeded()) { |
| + *result = enter.functions()->GetFlashAPI()->QueryFile( |
| + instance, path.c_str(), info); |
| + } |
| +} |
| + |
| +void PPB_Flash_Proxy::OnHostMsgGetDirContents( |
| + PP_Instance instance, |
| + const std::string& path, |
| + std::vector<SerializedDirEntry>* entries, |
| + int32_t* result) { |
| + EnterInstanceNoLock enter(instance); |
| + if (enter.failed()) |
| + return; |
| + |
| + PP_DirContents_Dev* contents = NULL; |
| + *result = enter.functions()->GetFlashAPI()->GetDirContents( |
| + instance, path.c_str(), &contents); |
| + if (*result != PP_OK) |
| + return; |
| + |
| + // Convert the list of entries to the serialized version. |
| + entries->resize(contents->count); |
| + for (int32_t i = 0; i < contents->count; i++) { |
| + (*entries)[i].name.assign(contents->entries[i].name); |
| + (*entries)[i].is_dir = PP_ToBool(contents->entries[i].is_dir); |
| + } |
| + enter.functions()->GetFlashAPI()->FreeDirContents(instance, contents); |
| +} |
| + |
| +void PPB_Flash_Proxy::OnHostMsgOpenFileRef( |
| + PP_Instance instance, |
| + const HostResource& host_resource, |
| + int32_t mode, |
| + IPC::PlatformFileForTransit* file_handle, |
| + int32_t* result) { |
| + EnterInstanceNoLock enter(instance); |
| + if (enter.failed()) { |
| + *result = PP_ERROR_BADARGUMENT; |
| + return; |
| + } |
| + |
| + base::PlatformFile file; |
| + *result = enter.functions()->GetFlashAPI()->OpenFileRef( |
| + instance, host_resource.host_resource(), mode, &file); |
| + *file_handle = PlatformFileToPlatformFileForTransit(dispatcher(), |
| + result, file); |
| +} |
| + |
| +void PPB_Flash_Proxy::OnHostMsgQueryFileRef( |
| + PP_Instance instance, |
| + const HostResource& host_resource, |
| + PP_FileInfo* info, |
| + int32_t* result) { |
| + EnterInstanceNoLock enter(instance); |
| + if (enter.failed()) { |
| + *result = PP_ERROR_BADARGUMENT; |
| + return; |
| + } |
| + *result = enter.functions()->GetFlashAPI()->QueryFileRef( |
| + instance, host_resource.host_resource(), info); |
| +} |
| + |
| } // namespace proxy |
| } // namespace ppapi |