OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ppapi/proxy/ppb_flash_proxy.h" | 5 #include "ppapi/proxy/ppb_flash_proxy.h" |
6 | 6 |
| 7 #include <map> |
| 8 #include <set> |
| 9 |
7 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/memory/ref_counted.h" |
8 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 13 #include "base/synchronization/lock.h" |
9 #include "base/time.h" | 14 #include "base/time.h" |
| 15 #include "ipc/ipc_channel_proxy.h" |
10 #include "ppapi/c/dev/ppb_font_dev.h" | 16 #include "ppapi/c/dev/ppb_font_dev.h" |
11 #include "ppapi/c/dev/ppb_var_deprecated.h" | 17 #include "ppapi/c/dev/ppb_var_deprecated.h" |
12 #include "ppapi/c/pp_errors.h" | 18 #include "ppapi/c/pp_errors.h" |
13 #include "ppapi/c/pp_resource.h" | 19 #include "ppapi/c/pp_resource.h" |
14 #include "ppapi/c/private/ppb_flash.h" | 20 #include "ppapi/c/private/ppb_flash.h" |
15 #include "ppapi/proxy/host_dispatcher.h" | 21 #include "ppapi/proxy/host_dispatcher.h" |
16 #include "ppapi/proxy/plugin_dispatcher.h" | 22 #include "ppapi/proxy/plugin_dispatcher.h" |
17 #include "ppapi/proxy/plugin_globals.h" | 23 #include "ppapi/proxy/plugin_globals.h" |
18 #include "ppapi/proxy/plugin_proxy_delegate.h" | 24 #include "ppapi/proxy/plugin_proxy_delegate.h" |
19 #include "ppapi/proxy/ppapi_messages.h" | 25 #include "ppapi/proxy/ppapi_messages.h" |
20 #include "ppapi/proxy/proxy_module.h" | 26 #include "ppapi/proxy/proxy_module.h" |
21 #include "ppapi/proxy/serialized_var.h" | 27 #include "ppapi/proxy/serialized_var.h" |
22 #include "ppapi/shared_impl/ppapi_globals.h" | 28 #include "ppapi/shared_impl/ppapi_globals.h" |
23 #include "ppapi/shared_impl/proxy_lock.h" | 29 #include "ppapi/shared_impl/proxy_lock.h" |
24 #include "ppapi/shared_impl/resource.h" | 30 #include "ppapi/shared_impl/resource.h" |
25 #include "ppapi/shared_impl/resource_tracker.h" | 31 #include "ppapi/shared_impl/resource_tracker.h" |
26 #include "ppapi/shared_impl/scoped_pp_resource.h" | 32 #include "ppapi/shared_impl/scoped_pp_resource.h" |
27 #include "ppapi/shared_impl/var.h" | 33 #include "ppapi/shared_impl/var.h" |
28 #include "ppapi/thunk/enter.h" | 34 #include "ppapi/thunk/enter.h" |
29 #include "ppapi/thunk/ppb_instance_api.h" | 35 #include "ppapi/thunk/ppb_instance_api.h" |
30 #include "ppapi/thunk/ppb_url_request_info_api.h" | 36 #include "ppapi/thunk/ppb_url_request_info_api.h" |
31 #include "ppapi/thunk/resource_creation_api.h" | 37 #include "ppapi/thunk/resource_creation_api.h" |
32 | 38 |
33 using ppapi::thunk::EnterInstanceNoLock; | 39 using ppapi::thunk::EnterInstanceNoLock; |
| 40 using ppapi::thunk::EnterResourceNoLock; |
34 | 41 |
35 namespace ppapi { | 42 namespace ppapi { |
36 namespace proxy { | 43 namespace proxy { |
37 | 44 |
| 45 namespace { |
| 46 |
| 47 IPC::PlatformFileForTransit PlatformFileToPlatformFileForTransit( |
| 48 Dispatcher* dispatcher, |
| 49 int32_t* error, |
| 50 base::PlatformFile file) { |
| 51 if (*error != PP_OK) |
| 52 return IPC::InvalidPlatformFileForTransit(); |
| 53 IPC::PlatformFileForTransit out_handle = |
| 54 dispatcher->ShareHandleWithRemote(file, true); |
| 55 if (out_handle == IPC::InvalidPlatformFileForTransit()) |
| 56 *error = PP_ERROR_NOACCESS; |
| 57 return out_handle; |
| 58 } |
| 59 |
| 60 // ModuleLocalThreadAdapter ---------------------------------------------------- |
| 61 // TODO(yzshen): Refactor to use IPC::SyncMessageFilter. |
| 62 class ModuleLocalThreadAdapter |
| 63 : public base::RefCountedThreadSafe<ModuleLocalThreadAdapter> { |
| 64 class Filter; |
| 65 public: |
| 66 ModuleLocalThreadAdapter(); |
| 67 |
| 68 void AddInstanceRouting(PP_Instance instance, Dispatcher* dispatcher); |
| 69 void ClearInstanceRouting(PP_Instance instance); |
| 70 void ClearFilter(Dispatcher* dispatcher, Filter* filter); |
| 71 |
| 72 bool OnModuleLocalMessageReceived(const IPC::Message& msg); |
| 73 |
| 74 // Called on the I/O thread when the channel is being destroyed and the |
| 75 // given message will never be issued a reply. |
| 76 void OnModuleLocalMessageFailed(int message_id); |
| 77 |
| 78 bool Send(PP_Instance instance, IPC::Message* msg); |
| 79 |
| 80 private: |
| 81 class Filter : public IPC::ChannelProxy::MessageFilter { |
| 82 public: |
| 83 explicit Filter(Dispatcher* dispatcher); |
| 84 ~Filter(); |
| 85 |
| 86 void Send(IPC::Message* msg); |
| 87 |
| 88 virtual void OnFilterAdded(IPC::Channel* channel); |
| 89 virtual void OnFilterRemoved(); |
| 90 virtual bool OnMessageReceived(const IPC::Message& message); |
| 91 |
| 92 private: |
| 93 // DO NOT DEREFERENCE! This is used only for tracking. |
| 94 Dispatcher* dispatcher_; |
| 95 |
| 96 IPC::Channel* channel_; |
| 97 |
| 98 // Holds the IPC messages that were sent before the channel was connected. |
| 99 // These will be sent ASAP. |
| 100 std::vector<IPC::Message*> pre_connect_pending_messages_; |
| 101 |
| 102 // Holds the IDs of the sync messages we're currently waiting on for this |
| 103 // channel. This tracking allows us to cancel those requests if the |
| 104 // remote process crashes and we're cleaning up this filter (without just |
| 105 // deadlocking the waiting thread(s). |
| 106 std::set<int> pending_requests_for_filter_; |
| 107 }; |
| 108 |
| 109 void SendFromIOThread(Dispatcher* dispatcher, IPC::Message* msg); |
| 110 |
| 111 // Internal version of OnModuleLocalMessageFailed which assumes the lock |
| 112 // is already held. |
| 113 void OnModuleLocalMessageFailedLocked(int message_id); |
| 114 |
| 115 base::Lock lock_; |
| 116 |
| 117 scoped_refptr<base::MessageLoopProxy> main_thread_; |
| 118 |
| 119 // Will be NULL before an instance routing is added. |
| 120 scoped_refptr<base::MessageLoopProxy> io_thread_; |
| 121 |
| 122 typedef std::map<PP_Instance, Dispatcher*> InstanceToDispatcher; |
| 123 InstanceToDispatcher instance_to_dispatcher_; |
| 124 |
| 125 // The filters are owned by the channel. |
| 126 typedef std::map<Dispatcher*, Filter*> DispatcherToFilter; |
| 127 DispatcherToFilter dispatcher_to_filter_; |
| 128 |
| 129 // Tracks all messages with currently waiting threads. This does not own |
| 130 // the pointer, the pointer lifetime is managed by Send(). |
| 131 typedef std::map<int, IPC::PendingSyncMsg*> SyncRequestMap; |
| 132 SyncRequestMap pending_sync_requests_; |
| 133 }; |
| 134 |
| 135 ModuleLocalThreadAdapter* g_module_local_thread_adapter = NULL; |
| 136 |
| 137 ModuleLocalThreadAdapter::Filter::Filter(Dispatcher* dispatcher) |
| 138 : dispatcher_(dispatcher), channel_(NULL) { |
| 139 } |
| 140 |
| 141 ModuleLocalThreadAdapter::Filter::~Filter() { |
| 142 } |
| 143 |
| 144 void ModuleLocalThreadAdapter::Filter::Send(IPC::Message* msg) { |
| 145 if (channel_) { |
| 146 int message_id = IPC::SyncMessage::GetMessageId(*msg); |
| 147 if (channel_->Send(msg)) |
| 148 pending_requests_for_filter_.insert(message_id); |
| 149 else // Message lost, notify adapter so it can unblock. |
| 150 g_module_local_thread_adapter->OnModuleLocalMessageFailed(message_id); |
| 151 } else { |
| 152 // No channel, save this message for when it's connected. |
| 153 pre_connect_pending_messages_.push_back(msg); |
| 154 } |
| 155 } |
| 156 |
| 157 void ModuleLocalThreadAdapter::Filter::OnFilterAdded(IPC::Channel* channel) { |
| 158 DCHECK(!channel_); |
| 159 channel_ = channel; |
| 160 |
| 161 // Now that we have a channel, process all pending messages. |
| 162 for (size_t i = 0; i < pre_connect_pending_messages_.size(); i++) |
| 163 Send(pre_connect_pending_messages_[i]); |
| 164 pre_connect_pending_messages_.clear(); |
| 165 } |
| 166 |
| 167 void ModuleLocalThreadAdapter::Filter::OnFilterRemoved() { |
| 168 DCHECK(channel_); |
| 169 channel_ = NULL; |
| 170 g_module_local_thread_adapter->ClearFilter(dispatcher_, this); |
| 171 |
| 172 for (std::set<int>::iterator i = pending_requests_for_filter_.begin(); |
| 173 i != pending_requests_for_filter_.end(); ++i) { |
| 174 g_module_local_thread_adapter->OnModuleLocalMessageFailed(*i); |
| 175 } |
| 176 } |
| 177 |
| 178 bool ModuleLocalThreadAdapter::Filter::OnMessageReceived( |
| 179 const IPC::Message& message) { |
| 180 if (!message.is_reply() || |
| 181 message.routing_id() != API_ID_PPB_FLASH) |
| 182 return false; |
| 183 |
| 184 if (g_module_local_thread_adapter->OnModuleLocalMessageReceived(message)) { |
| 185 // The message was consumed, this means we can remove the message ID from |
| 186 // the list of messages this channel is waiting on. |
| 187 pending_requests_for_filter_.erase(IPC::SyncMessage::GetMessageId(message)); |
| 188 return true; |
| 189 } |
| 190 return false; |
| 191 } |
| 192 |
| 193 ModuleLocalThreadAdapter::ModuleLocalThreadAdapter() |
| 194 : main_thread_(base::MessageLoopProxy::current()) { |
| 195 } |
| 196 |
| 197 void ModuleLocalThreadAdapter::AddInstanceRouting(PP_Instance instance, |
| 198 Dispatcher* dispatcher) { |
| 199 base::AutoLock lock(lock_); |
| 200 |
| 201 // Now that we've had contact with a dispatcher, we can set up the IO thread. |
| 202 DCHECK(main_thread_->BelongsToCurrentThread()); |
| 203 if (!io_thread_.get()) |
| 204 io_thread_ = dispatcher->GetIPCMessageLoop(); |
| 205 |
| 206 // Set up the instance -> dispatcher routing. |
| 207 DCHECK(instance_to_dispatcher_.find(instance) == |
| 208 instance_to_dispatcher_.end()); |
| 209 instance_to_dispatcher_[instance] = dispatcher; |
| 210 |
| 211 DispatcherToFilter::iterator found_filter = |
| 212 dispatcher_to_filter_.find(dispatcher); |
| 213 if (found_filter == dispatcher_to_filter_.end()) { |
| 214 // Need to set up a filter for this dispatcher to intercept the messages. |
| 215 Filter* filter = new Filter(dispatcher); |
| 216 dispatcher_to_filter_[dispatcher] = filter; |
| 217 dispatcher->AddIOThreadMessageFilter(filter); |
| 218 } |
| 219 } |
| 220 |
| 221 void ModuleLocalThreadAdapter::ClearInstanceRouting(PP_Instance instance) { |
| 222 // The dispatcher->filter mapping is cleaned up by ClearFilter which is |
| 223 // initiated by the channel. |
| 224 instance_to_dispatcher_.erase(instance); |
| 225 } |
| 226 |
| 227 void ModuleLocalThreadAdapter::ClearFilter(Dispatcher* dispatcher, |
| 228 Filter* filter) { |
| 229 // DANGER! Don't dereference the dispatcher, it's just used to identify |
| 230 // which filter to remove. The dispatcher may not even exist any more. |
| 231 // |
| 232 // Since the dispatcher may be gone, there's a potential for ambiguity if |
| 233 // another one is created on the main thread before this code runs on the |
| 234 // I/O thread. So we check that the filter matches to avoid this rare case. |
| 235 base::AutoLock lock(lock_); |
| 236 if (dispatcher_to_filter_[dispatcher] == filter) |
| 237 dispatcher_to_filter_.erase(dispatcher); |
| 238 } |
| 239 |
| 240 bool ModuleLocalThreadAdapter::OnModuleLocalMessageReceived( |
| 241 const IPC::Message& msg) { |
| 242 base::AutoLock lock(lock_); |
| 243 |
| 244 int message_id = IPC::SyncMessage::GetMessageId(msg); |
| 245 SyncRequestMap::iterator found = pending_sync_requests_.find(message_id); |
| 246 if (found == pending_sync_requests_.end()) { |
| 247 // Not waiting for this event. This will happen for sync messages to the |
| 248 // main thread which use the "regular" sync channel code path. |
| 249 return false; |
| 250 } |
| 251 |
| 252 IPC::PendingSyncMsg& info = *found->second; |
| 253 |
| 254 if (!msg.is_reply_error()) |
| 255 info.deserializer->SerializeOutputParameters(msg); |
| 256 info.done_event->Signal(); |
| 257 return true; |
| 258 } |
| 259 |
| 260 void ModuleLocalThreadAdapter::OnModuleLocalMessageFailed(int message_id) { |
| 261 base::AutoLock lock(lock_); |
| 262 OnModuleLocalMessageFailedLocked(message_id); |
| 263 } |
| 264 |
| 265 bool ModuleLocalThreadAdapter::Send(PP_Instance instance, IPC::Message* msg) { |
| 266 // Compute the dispatcher corresponding to this message. |
| 267 Dispatcher* dispatcher = NULL; |
| 268 { |
| 269 base::AutoLock lock(lock_); |
| 270 InstanceToDispatcher::iterator found = |
| 271 instance_to_dispatcher_.find(instance); |
| 272 if (found == instance_to_dispatcher_.end()) { |
| 273 NOTREACHED(); |
| 274 delete msg; |
| 275 return false; |
| 276 } |
| 277 dispatcher = found->second; |
| 278 } |
| 279 |
| 280 if (main_thread_->BelongsToCurrentThread()) { |
| 281 // Easy case: We're on the same thread as the dispatcher, so we don't need |
| 282 // a lock to access it, and we can just use the normal sync channel stuff |
| 283 // to handle the message. Actually, we MUST use the normal sync channel |
| 284 // stuff since there may be incoming sync messages that need processing. |
| 285 // The code below doesn't handle any nested message loops. |
| 286 return dispatcher->Send(msg); |
| 287 } |
| 288 |
| 289 // Background thread case |
| 290 // ---------------------- |
| 291 // 1. Generate tracking info, stick in pending_sync_messages_map. |
| 292 // 2. Kick off the request. This is done on the I/O thread. |
| 293 // 3. Filter on the I/O thread notices reply, writes the reply data and |
| 294 // signals the event. We block on the event while this is happening. |
| 295 // 4. Remove tracking info. |
| 296 |
| 297 // Generate the tracking info. and copied |
| 298 IPC::SyncMessage* sync_msg = static_cast<IPC::SyncMessage*>(msg); |
| 299 int message_id = IPC::SyncMessage::GetMessageId(*sync_msg); |
| 300 base::WaitableEvent event(true, false); |
| 301 scoped_ptr<IPC::MessageReplyDeserializer> deserializer( |
| 302 sync_msg->GetReplyDeserializer()); // We own this pointer once retrieved. |
| 303 IPC::PendingSyncMsg info(message_id, deserializer.get(), &event); |
| 304 |
| 305 // Add the tracking information to our map. |
| 306 { |
| 307 base::AutoLock lock(lock_); |
| 308 pending_sync_requests_[message_id] = &info; |
| 309 } |
| 310 |
| 311 // This is a bit dangerous. We use the dispatcher pointer as the routing |
| 312 // ID for this message. While we don't dereference it, there is an |
| 313 // exceedingly remote possibility that while this is going to the background |
| 314 // thread the connection will be shut down and a new one will be created with |
| 315 // a dispatcher at the same address. It could potentially get sent to a |
| 316 // random place, but it should actually still work (since the Flash file |
| 317 // operations are global). |
| 318 io_thread_->PostTask(FROM_HERE, |
| 319 base::Bind(&ModuleLocalThreadAdapter::SendFromIOThread, this, |
| 320 dispatcher, msg)); |
| 321 |
| 322 // Now we block the current thread waiting for the reply. |
| 323 event.Wait(); |
| 324 |
| 325 { |
| 326 // Clear our tracking info for this message now that we're done. |
| 327 base::AutoLock lock(lock_); |
| 328 DCHECK(pending_sync_requests_.find(message_id) != |
| 329 pending_sync_requests_.end()); |
| 330 pending_sync_requests_.erase(message_id); |
| 331 } |
| 332 |
| 333 return true; |
| 334 } |
| 335 |
| 336 void ModuleLocalThreadAdapter::SendFromIOThread(Dispatcher* dispatcher, |
| 337 IPC::Message* msg) { |
| 338 // DO NOT DEREFERENCE DISPATCHER. Used as a lookup only. |
| 339 base::AutoLock lock(lock_); |
| 340 DispatcherToFilter::iterator found = dispatcher_to_filter_.find(dispatcher); |
| 341 |
| 342 // The dispatcher could have been destroyed by the time we got here since |
| 343 // we're on another thread. Need to unblock the caller. |
| 344 if (found == dispatcher_to_filter_.end()) { |
| 345 OnModuleLocalMessageFailedLocked(IPC::SyncMessage::GetMessageId(*msg)); |
| 346 delete msg; |
| 347 return; |
| 348 } |
| 349 |
| 350 // Takes ownership of pointer. |
| 351 found->second->Send(msg); |
| 352 } |
| 353 |
| 354 void ModuleLocalThreadAdapter::OnModuleLocalMessageFailedLocked( |
| 355 int message_id) { |
| 356 lock_.AssertAcquired(); |
| 357 |
| 358 // Unblock the thread waiting for the message that will never come. |
| 359 SyncRequestMap::iterator found = pending_sync_requests_.find(message_id); |
| 360 if (found == pending_sync_requests_.end()) { |
| 361 NOTREACHED(); |
| 362 return; |
| 363 } |
| 364 found->second->done_event->Signal(); |
| 365 } |
| 366 |
| 367 } // namespace |
| 368 |
| 369 // ----------------------------------------------------------------------------- |
| 370 |
38 PPB_Flash_Proxy::PPB_Flash_Proxy(Dispatcher* dispatcher) | 371 PPB_Flash_Proxy::PPB_Flash_Proxy(Dispatcher* dispatcher) |
39 : InterfaceProxy(dispatcher) { | 372 : InterfaceProxy(dispatcher) { |
40 } | 373 } |
41 | 374 |
42 PPB_Flash_Proxy::~PPB_Flash_Proxy() { | 375 PPB_Flash_Proxy::~PPB_Flash_Proxy() { |
43 } | 376 } |
44 | 377 |
45 bool PPB_Flash_Proxy::OnMessageReceived(const IPC::Message& msg) { | 378 bool PPB_Flash_Proxy::OnMessageReceived(const IPC::Message& msg) { |
46 // Prevent the dispatcher from going away during a call to Navigate. | 379 // Prevent the dispatcher from going away during a call to Navigate. |
47 // This must happen OUTSIDE of OnMsgNavigate since the handling code use | 380 // This must happen OUTSIDE of OnMsgNavigate since the handling code use |
(...skipping 20 matching lines...) Expand all Loading... |
68 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_FlashSetFullscreen, | 401 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_FlashSetFullscreen, |
69 OnHostMsgFlashSetFullscreen) | 402 OnHostMsgFlashSetFullscreen) |
70 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_FlashGetScreenSize, | 403 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_FlashGetScreenSize, |
71 OnHostMsgFlashGetScreenSize) | 404 OnHostMsgFlashGetScreenSize) |
72 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_IsClipboardFormatAvailable, | 405 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_IsClipboardFormatAvailable, |
73 OnHostMsgIsClipboardFormatAvailable) | 406 OnHostMsgIsClipboardFormatAvailable) |
74 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_ReadClipboardData, | 407 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_ReadClipboardData, |
75 OnHostMsgReadClipboardData) | 408 OnHostMsgReadClipboardData) |
76 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_WriteClipboardData, | 409 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_WriteClipboardData, |
77 OnHostMsgWriteClipboardData) | 410 OnHostMsgWriteClipboardData) |
| 411 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_OpenFile, |
| 412 OnHostMsgOpenFile) |
| 413 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_RenameFile, |
| 414 OnHostMsgRenameFile) |
| 415 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_DeleteFileOrDir, |
| 416 OnHostMsgDeleteFileOrDir) |
| 417 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_CreateDir, |
| 418 OnHostMsgCreateDir) |
| 419 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_QueryFile, |
| 420 OnHostMsgQueryFile) |
| 421 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_GetDirContents, |
| 422 OnHostMsgGetDirContents) |
| 423 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_OpenFileRef, |
| 424 OnHostMsgOpenFileRef) |
| 425 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_QueryFileRef, |
| 426 OnHostMsgQueryFileRef) |
78 IPC_MESSAGE_UNHANDLED(handled = false) | 427 IPC_MESSAGE_UNHANDLED(handled = false) |
79 IPC_END_MESSAGE_MAP() | 428 IPC_END_MESSAGE_MAP() |
80 // TODO(brettw) handle bad messages! | 429 // TODO(brettw) handle bad messages! |
81 return handled; | 430 return handled; |
82 } | 431 } |
83 | 432 |
84 void PPB_Flash_Proxy::SetInstanceAlwaysOnTop(PP_Instance instance, | 433 void PPB_Flash_Proxy::SetInstanceAlwaysOnTop(PP_Instance instance, |
85 PP_Bool on_top) { | 434 PP_Bool on_top) { |
86 dispatcher()->Send(new PpapiHostMsg_PPBFlash_SetInstanceAlwaysOnTop( | 435 dispatcher()->Send(new PpapiHostMsg_PPBFlash_SetInstanceAlwaysOnTop( |
87 API_ID_PPB_FLASH, instance, on_top)); | 436 API_ID_PPB_FLASH, instance, on_top)); |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 dispatcher()->Send(new PpapiHostMsg_PPBFlash_WriteClipboardData( | 610 dispatcher()->Send(new PpapiHostMsg_PPBFlash_WriteClipboardData( |
262 API_ID_PPB_FLASH, | 611 API_ID_PPB_FLASH, |
263 instance, | 612 instance, |
264 static_cast<int>(clipboard_type), | 613 static_cast<int>(clipboard_type), |
265 formats_vector, | 614 formats_vector, |
266 data_items_vector)); | 615 data_items_vector)); |
267 // Assume success, since it allows us to avoid a sync IPC. | 616 // Assume success, since it allows us to avoid a sync IPC. |
268 return PP_OK; | 617 return PP_OK; |
269 } | 618 } |
270 | 619 |
| 620 bool PPB_Flash_Proxy::CreateThreadAdapterForInstance(PP_Instance instance) { |
| 621 if (!g_module_local_thread_adapter) { |
| 622 g_module_local_thread_adapter = new ModuleLocalThreadAdapter(); |
| 623 g_module_local_thread_adapter->AddRef(); // Leaked, this object is global. |
| 624 } |
| 625 |
| 626 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); |
| 627 if (!dispatcher) { |
| 628 NOTREACHED(); |
| 629 return false; |
| 630 } |
| 631 g_module_local_thread_adapter->AddInstanceRouting(instance, dispatcher); |
| 632 return true; |
| 633 } |
| 634 |
| 635 void PPB_Flash_Proxy::ClearThreadAdapterForInstance(PP_Instance instance) { |
| 636 if (g_module_local_thread_adapter) |
| 637 g_module_local_thread_adapter->ClearInstanceRouting(instance); |
| 638 } |
| 639 |
| 640 int32_t PPB_Flash_Proxy::OpenFile(PP_Instance instance, |
| 641 const char* path, |
| 642 int32_t mode, |
| 643 PP_FileHandle* file) { |
| 644 if (!g_module_local_thread_adapter) |
| 645 return PP_ERROR_FAILED; |
| 646 |
| 647 int32_t result = PP_ERROR_FAILED; |
| 648 IPC::PlatformFileForTransit transit; |
| 649 g_module_local_thread_adapter->Send(instance, |
| 650 new PpapiHostMsg_PPBFlash_OpenFile( |
| 651 API_ID_PPB_FLASH, instance, path, mode, &transit, &result)); |
| 652 *file = IPC::PlatformFileForTransitToPlatformFile(transit); |
| 653 return result; |
| 654 } |
| 655 |
| 656 int32_t PPB_Flash_Proxy::RenameFile(PP_Instance instance, |
| 657 const char* path_from, |
| 658 const char* path_to) { |
| 659 if (!g_module_local_thread_adapter) |
| 660 return PP_ERROR_FAILED; |
| 661 |
| 662 int32_t result = PP_ERROR_FAILED; |
| 663 g_module_local_thread_adapter->Send(instance, |
| 664 new PpapiHostMsg_PPBFlash_RenameFile( |
| 665 API_ID_PPB_FLASH, instance, path_from, path_to, &result)); |
| 666 return result; |
| 667 } |
| 668 |
| 669 int32_t PPB_Flash_Proxy::DeleteFileOrDir(PP_Instance instance, |
| 670 const char* path, |
| 671 PP_Bool recursive) { |
| 672 if (!g_module_local_thread_adapter) |
| 673 return PP_ERROR_FAILED; |
| 674 |
| 675 int32_t result = PP_ERROR_FAILED; |
| 676 g_module_local_thread_adapter->Send(instance, |
| 677 new PpapiHostMsg_PPBFlash_DeleteFileOrDir( |
| 678 API_ID_PPB_FLASH, instance, path, recursive, &result)); |
| 679 return result; |
| 680 } |
| 681 |
| 682 int32_t PPB_Flash_Proxy::CreateDir(PP_Instance instance, const char* path) { |
| 683 if (!g_module_local_thread_adapter) |
| 684 return PP_ERROR_FAILED; |
| 685 |
| 686 int32_t result = PP_ERROR_FAILED; |
| 687 g_module_local_thread_adapter->Send(instance, |
| 688 new PpapiHostMsg_PPBFlash_CreateDir( |
| 689 API_ID_PPB_FLASH, instance, path, &result)); |
| 690 return result; |
| 691 } |
| 692 |
| 693 int32_t PPB_Flash_Proxy::QueryFile(PP_Instance instance, |
| 694 const char* path, |
| 695 PP_FileInfo* info) { |
| 696 if (!g_module_local_thread_adapter) |
| 697 return PP_ERROR_FAILED; |
| 698 |
| 699 int32_t result = PP_ERROR_FAILED; |
| 700 g_module_local_thread_adapter->Send(instance, |
| 701 new PpapiHostMsg_PPBFlash_QueryFile( |
| 702 API_ID_PPB_FLASH, instance, path, info, &result)); |
| 703 return result; |
| 704 } |
| 705 |
| 706 int32_t PPB_Flash_Proxy::GetDirContents(PP_Instance instance, |
| 707 const char* path, |
| 708 PP_DirContents_Dev** contents) { |
| 709 if (!g_module_local_thread_adapter) |
| 710 return PP_ERROR_FAILED; |
| 711 |
| 712 int32_t result = PP_ERROR_FAILED; |
| 713 std::vector<SerializedDirEntry> entries; |
| 714 g_module_local_thread_adapter->Send(instance, |
| 715 new PpapiHostMsg_PPBFlash_GetDirContents( |
| 716 API_ID_PPB_FLASH, instance, path, &entries, &result)); |
| 717 |
| 718 if (result != PP_OK) |
| 719 return result; |
| 720 |
| 721 // Copy the serialized dir entries to the output struct. |
| 722 *contents = new PP_DirContents_Dev; |
| 723 (*contents)->count = static_cast<int32_t>(entries.size()); |
| 724 (*contents)->entries = new PP_DirEntry_Dev[entries.size()]; |
| 725 for (size_t i = 0; i < entries.size(); i++) { |
| 726 const SerializedDirEntry& source = entries[i]; |
| 727 PP_DirEntry_Dev* dest = &(*contents)->entries[i]; |
| 728 |
| 729 char* name_copy = new char[source.name.size() + 1]; |
| 730 memcpy(name_copy, source.name.c_str(), source.name.size() + 1); |
| 731 dest->name = name_copy; |
| 732 dest->is_dir = PP_FromBool(source.is_dir); |
| 733 } |
| 734 |
| 735 return result; |
| 736 } |
| 737 |
| 738 int32_t PPB_Flash_Proxy::OpenFileRef(PP_Instance instance, |
| 739 PP_Resource file_ref_id, |
| 740 int32_t mode, |
| 741 PP_FileHandle* file) { |
| 742 EnterResourceNoLock<PPB_FileRef> enter(file_ref_id, true); |
| 743 if (enter.failed()) |
| 744 return PP_ERROR_BADRESOURCE; |
| 745 |
| 746 int32_t result = PP_ERROR_FAILED; |
| 747 IPC::PlatformFileForTransit transit; |
| 748 dispatcher()->Send(new PpapiHostMsg_PPBFlash_OpenFileRef( |
| 749 API_ID_PPB_FLASH, instance, enter.resource()->host_resource(), mode, |
| 750 &transit, &result)); |
| 751 *file = IPC::PlatformFileForTransitToPlatformFile(transit); |
| 752 return result; |
| 753 } |
| 754 |
| 755 int32_t PPB_Flash_Proxy::QueryFileRef(PP_Instance instance, |
| 756 PP_Resource file_ref_id, |
| 757 PP_FileInfo* info) { |
| 758 EnterResourceNoLock<PPB_FileRef> enter(file_ref_id, true); |
| 759 if (enter.failed()) |
| 760 return PP_ERROR_BADRESOURCE; |
| 761 |
| 762 int32_t result = PP_ERROR_FAILED; |
| 763 dispatcher()->Send(new PpapiHostMsg_PPBFlash_QueryFileRef( |
| 764 API_ID_PPB_FLASH, instance, enter.resource()->host_resource(), info, |
| 765 &result)); |
| 766 return result; |
| 767 } |
| 768 |
271 PP_Bool PPB_Flash_Proxy::FlashIsFullscreen(PP_Instance instance) { | 769 PP_Bool PPB_Flash_Proxy::FlashIsFullscreen(PP_Instance instance) { |
272 InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())-> | 770 InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())-> |
273 GetInstanceData(instance); | 771 GetInstanceData(instance); |
274 if (!data) | 772 if (!data) |
275 return PP_FALSE; | 773 return PP_FALSE; |
276 return data->flash_fullscreen; | 774 return data->flash_fullscreen; |
277 } | 775 } |
278 | 776 |
279 PP_Bool PPB_Flash_Proxy::FlashSetFullscreen(PP_Instance instance, | 777 PP_Bool PPB_Flash_Proxy::FlashSetFullscreen(PP_Instance instance, |
280 PP_Bool fullscreen) { | 778 PP_Bool fullscreen) { |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 static_cast<PP_Flash_Clipboard_Type>(clipboard_type), | 991 static_cast<PP_Flash_Clipboard_Type>(clipboard_type), |
494 data_item_count, | 992 data_item_count, |
495 formats_array.get(), | 993 formats_array.get(), |
496 data_items_array); | 994 data_items_array); |
497 DLOG_IF(WARNING, result != PP_OK) | 995 DLOG_IF(WARNING, result != PP_OK) |
498 << "Write to clipboard failed unexpectedly."; | 996 << "Write to clipboard failed unexpectedly."; |
499 (void)result; // Prevent warning in release mode. | 997 (void)result; // Prevent warning in release mode. |
500 } | 998 } |
501 } | 999 } |
502 | 1000 |
| 1001 void PPB_Flash_Proxy::OnHostMsgOpenFile( |
| 1002 PP_Instance instance, |
| 1003 const std::string& path, |
| 1004 int32_t mode, |
| 1005 IPC::PlatformFileForTransit* file_handle, |
| 1006 int32_t* result) { |
| 1007 EnterInstanceNoLock enter(instance); |
| 1008 if (enter.succeeded()) { |
| 1009 base::PlatformFile file; |
| 1010 *result = enter.functions()->GetFlashAPI()->OpenFile( |
| 1011 instance, path.c_str(), mode, &file); |
| 1012 *file_handle = PlatformFileToPlatformFileForTransit( |
| 1013 dispatcher(), result, file); |
| 1014 } else { |
| 1015 *result = PP_ERROR_BADARGUMENT; |
| 1016 } |
| 1017 } |
| 1018 |
| 1019 void PPB_Flash_Proxy::OnHostMsgRenameFile(PP_Instance instance, |
| 1020 const std::string& from_path, |
| 1021 const std::string& to_path, |
| 1022 int32_t* result) { |
| 1023 EnterInstanceNoLock enter(instance); |
| 1024 if (enter.succeeded()) { |
| 1025 *result = enter.functions()->GetFlashAPI()->RenameFile( |
| 1026 instance, from_path.c_str(), to_path.c_str()); |
| 1027 } else { |
| 1028 *result = PP_ERROR_BADARGUMENT; |
| 1029 } |
| 1030 } |
| 1031 |
| 1032 void PPB_Flash_Proxy::OnHostMsgDeleteFileOrDir(PP_Instance instance, |
| 1033 const std::string& path, |
| 1034 PP_Bool recursive, |
| 1035 int32_t* result) { |
| 1036 EnterInstanceNoLock enter(instance); |
| 1037 if (enter.succeeded()) { |
| 1038 *result = enter.functions()->GetFlashAPI()->DeleteFileOrDir( |
| 1039 instance, path.c_str(), recursive); |
| 1040 } else { |
| 1041 *result = PP_ERROR_BADARGUMENT; |
| 1042 } |
| 1043 } |
| 1044 |
| 1045 void PPB_Flash_Proxy::OnHostMsgCreateDir(PP_Instance instance, |
| 1046 const std::string& path, |
| 1047 int32_t* result) { |
| 1048 EnterInstanceNoLock enter(instance); |
| 1049 if (enter.succeeded()) { |
| 1050 *result = enter.functions()->GetFlashAPI()->CreateDir( |
| 1051 instance, path.c_str()); |
| 1052 } else { |
| 1053 *result = PP_ERROR_BADARGUMENT; |
| 1054 } |
| 1055 } |
| 1056 |
| 1057 void PPB_Flash_Proxy::OnHostMsgQueryFile(PP_Instance instance, |
| 1058 const std::string& path, |
| 1059 PP_FileInfo* info, |
| 1060 int32_t* result) { |
| 1061 EnterInstanceNoLock enter(instance); |
| 1062 if (enter.succeeded()) { |
| 1063 *result = enter.functions()->GetFlashAPI()->QueryFile( |
| 1064 instance, path.c_str(), info); |
| 1065 } else { |
| 1066 *result = PP_ERROR_BADARGUMENT; |
| 1067 } |
| 1068 } |
| 1069 |
| 1070 void PPB_Flash_Proxy::OnHostMsgGetDirContents( |
| 1071 PP_Instance instance, |
| 1072 const std::string& path, |
| 1073 std::vector<SerializedDirEntry>* entries, |
| 1074 int32_t* result) { |
| 1075 EnterInstanceNoLock enter(instance); |
| 1076 if (enter.failed()) { |
| 1077 *result = PP_ERROR_BADARGUMENT; |
| 1078 return; |
| 1079 } |
| 1080 |
| 1081 PP_DirContents_Dev* contents = NULL; |
| 1082 *result = enter.functions()->GetFlashAPI()->GetDirContents( |
| 1083 instance, path.c_str(), &contents); |
| 1084 if (*result != PP_OK) |
| 1085 return; |
| 1086 |
| 1087 // Convert the list of entries to the serialized version. |
| 1088 entries->resize(contents->count); |
| 1089 for (int32_t i = 0; i < contents->count; i++) { |
| 1090 (*entries)[i].name.assign(contents->entries[i].name); |
| 1091 (*entries)[i].is_dir = PP_ToBool(contents->entries[i].is_dir); |
| 1092 } |
| 1093 enter.functions()->GetFlashAPI()->FreeDirContents(instance, contents); |
| 1094 } |
| 1095 |
| 1096 void PPB_Flash_Proxy::OnHostMsgOpenFileRef( |
| 1097 PP_Instance instance, |
| 1098 const HostResource& host_resource, |
| 1099 int32_t mode, |
| 1100 IPC::PlatformFileForTransit* file_handle, |
| 1101 int32_t* result) { |
| 1102 EnterInstanceNoLock enter(instance); |
| 1103 if (enter.failed()) { |
| 1104 *result = PP_ERROR_BADARGUMENT; |
| 1105 return; |
| 1106 } |
| 1107 |
| 1108 base::PlatformFile file; |
| 1109 *result = enter.functions()->GetFlashAPI()->OpenFileRef( |
| 1110 instance, host_resource.host_resource(), mode, &file); |
| 1111 *file_handle = PlatformFileToPlatformFileForTransit(dispatcher(), |
| 1112 result, file); |
| 1113 } |
| 1114 |
| 1115 void PPB_Flash_Proxy::OnHostMsgQueryFileRef( |
| 1116 PP_Instance instance, |
| 1117 const HostResource& host_resource, |
| 1118 PP_FileInfo* info, |
| 1119 int32_t* result) { |
| 1120 EnterInstanceNoLock enter(instance); |
| 1121 if (enter.failed()) { |
| 1122 *result = PP_ERROR_BADARGUMENT; |
| 1123 return; |
| 1124 } |
| 1125 *result = enter.functions()->GetFlashAPI()->QueryFileRef( |
| 1126 instance, host_resource.host_resource(), info); |
| 1127 } |
| 1128 |
503 } // namespace proxy | 1129 } // namespace proxy |
504 } // namespace ppapi | 1130 } // namespace ppapi |
OLD | NEW |