1// Copyright 2014 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 "ppapi/proxy/message_handler.h" 6 7#include "ipc/ipc_message.h" 8#include "ppapi/proxy/plugin_dispatcher.h" 9#include "ppapi/proxy/ppapi_messages.h" 10#include "ppapi/proxy/ppb_message_loop_proxy.h" 11#include "ppapi/shared_impl/proxy_lock.h" 12#include "ppapi/shared_impl/scoped_pp_var.h" 13#include "ppapi/thunk/enter.h" 14 15namespace ppapi { 16namespace proxy { 17namespace { 18 19typedef void (*HandleMessageFunc)(PP_Instance, void*, PP_Var); 20typedef PP_Var (*HandleBlockingMessageFunc)(PP_Instance, void*, PP_Var); 21 22void HandleMessageWrapper(HandleMessageFunc function, 23 PP_Instance instance, 24 void* user_data, 25 ScopedPPVar message_data) { 26 CallWhileUnlocked(function, instance, user_data, message_data.get()); 27} 28 29void HandleBlockingMessageWrapper(HandleBlockingMessageFunc function, 30 PP_Instance instance, 31 void* user_data, 32 ScopedPPVar message_data, 33 scoped_ptr<IPC::Message> reply_msg) { 34 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); 35 if (!dispatcher) 36 return; 37 PP_Var return_value = CallWhileUnlocked(function, 38 instance, 39 user_data, 40 message_data.get()); 41 PpapiMsg_PPPMessageHandler_HandleBlockingMessage::WriteReplyParams( 42 reply_msg.get(), 43 SerializedVarReturnValue::Convert(dispatcher, return_value), 44 true /* was_handled */); 45 dispatcher->Send(reply_msg.release()); 46} 47 48} // namespace 49 50// static 51scoped_ptr<MessageHandler> MessageHandler::Create( 52 PP_Instance instance, 53 const PPP_MessageHandler_0_1* handler_if, 54 void* user_data, 55 PP_Resource message_loop, 56 int32_t* error) { 57 scoped_ptr<MessageHandler> result; 58 // The interface and all function pointers must be valid. 59 if (!handler_if || 60 !handler_if->HandleMessage || 61 !handler_if->HandleBlockingMessage || 62 !handler_if->Destroy) { 63 *error = PP_ERROR_BADARGUMENT; 64 return result.Pass(); 65 } 66 thunk::EnterResourceNoLock<thunk::PPB_MessageLoop_API> 67 enter_loop(message_loop, true); 68 if (enter_loop.failed()) { 69 *error = PP_ERROR_BADRESOURCE; 70 return result.Pass(); 71 } 72 scoped_refptr<MessageLoopResource> message_loop_resource( 73 static_cast<MessageLoopResource*>(enter_loop.object())); 74 if (message_loop_resource->is_main_thread_loop()) { 75 *error = PP_ERROR_WRONG_THREAD; 76 return result.Pass(); 77 } 78 79 result.reset(new MessageHandler( 80 instance, handler_if, user_data, message_loop_resource)); 81 *error = PP_OK; 82 return result.Pass(); 83} 84 85MessageHandler::~MessageHandler() { 86 // It's possible the message_loop_proxy is NULL if that loop has been quit. 87 // In that case, we unfortunately just can't call Destroy. 88 if (message_loop_->message_loop_proxy()) { 89 // The posted task won't have the proxy lock, but that's OK, it doesn't 90 // touch any internal state; it's a direct call on the plugin's function. 91 message_loop_->message_loop_proxy()->PostTask(FROM_HERE, 92 base::Bind(handler_if_->Destroy, 93 instance_, 94 user_data_)); 95 } 96} 97 98bool MessageHandler::LoopIsValid() const { 99 return !!message_loop_->message_loop_proxy(); 100} 101 102void MessageHandler::HandleMessage(ScopedPPVar var) { 103 message_loop_->message_loop_proxy()->PostTask(FROM_HERE, 104 RunWhileLocked(base::Bind(&HandleMessageWrapper, 105 handler_if_->HandleMessage, 106 instance_, 107 user_data_, 108 var))); 109} 110 111void MessageHandler::HandleBlockingMessage(ScopedPPVar var, 112 scoped_ptr<IPC::Message> reply_msg) { 113 message_loop_->message_loop_proxy()->PostTask(FROM_HERE, 114 RunWhileLocked(base::Bind(&HandleBlockingMessageWrapper, 115 handler_if_->HandleBlockingMessage, 116 instance_, 117 user_data_, 118 var, 119 base::Passed(reply_msg.Pass())))); 120} 121 122MessageHandler::MessageHandler( 123 PP_Instance instance, 124 const PPP_MessageHandler_0_1* handler_if, 125 void* user_data, 126 scoped_refptr<MessageLoopResource> message_loop) 127 : instance_(instance), 128 handler_if_(handler_if), 129 user_data_(user_data), 130 message_loop_(message_loop) { 131} 132 133} // namespace proxy 134} // namespace ppapi 135