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 15 namespace ppapi { 16 namespace proxy { 17 namespace { 18 19 typedef void (*HandleMessageFunc)(PP_Instance, void*, const PP_Var*); 20 typedef void (*HandleBlockingMessageFunc)( 21 PP_Instance, void*, const PP_Var*, PP_Var*); 22 typedef void (*HandleMessageFunc_0_1)(PP_Instance, void*, PP_Var); 23 typedef PP_Var (*HandleBlockingMessageFunc_0_1)(PP_Instance, void*, PP_Var); 24 25 void HandleMessageWrapper(HandleMessageFunc function, 26 PP_Instance instance, 27 void* user_data, 28 ScopedPPVar message_data) { 29 CallWhileUnlocked(function, instance, user_data, 30 &message_data.get()); 31 } 32 33 void HandleBlockingMessageWrapper(HandleBlockingMessageFunc function, 34 PP_Instance instance, 35 void* user_data, 36 ScopedPPVar message_data, 37 scoped_ptr<IPC::Message> reply_msg) { 38 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); 39 if (!dispatcher) 40 return; 41 PP_Var result = PP_MakeUndefined(); 42 MessageLoopResource::GetCurrent()-> 43 set_currently_handling_blocking_message(true); 44 CallWhileUnlocked( 45 function, instance, user_data, &message_data.get(), &result); 46 MessageLoopResource::GetCurrent()-> 47 set_currently_handling_blocking_message(false); 48 PpapiMsg_PPPMessageHandler_HandleBlockingMessage::WriteReplyParams( 49 reply_msg.get(), 50 SerializedVarReturnValue::Convert(dispatcher, result), 51 true /* was_handled */); 52 dispatcher->Send(reply_msg.release()); 53 } 54 55 // TODO(dmichael): Remove the 0_1 verions; crbug.com/414398 56 void HandleMessageWrapper_0_1(HandleMessageFunc_0_1 function, 57 PP_Instance instance, 58 void* user_data, 59 ScopedPPVar message_data) { 60 CallWhileUnlocked(function, instance, user_data, message_data.get()); 61 } 62 63 void HandleBlockingMessageWrapper_0_1(HandleBlockingMessageFunc_0_1 function, 64 PP_Instance instance, 65 void* user_data, 66 ScopedPPVar message_data, 67 scoped_ptr<IPC::Message> reply_msg) { 68 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); 69 if (!dispatcher) 70 return; 71 MessageLoopResource::GetCurrent()-> 72 set_currently_handling_blocking_message(true); 73 PP_Var return_value = CallWhileUnlocked(function, 74 instance, 75 user_data, 76 message_data.get()); 77 MessageLoopResource::GetCurrent()-> 78 set_currently_handling_blocking_message(false); 79 PpapiMsg_PPPMessageHandler_HandleBlockingMessage::WriteReplyParams( 80 reply_msg.get(), 81 SerializedVarReturnValue::Convert(dispatcher, return_value), 82 true /* was_handled */); 83 dispatcher->Send(reply_msg.release()); 84 } 85 86 } // namespace 87 88 // static 89 scoped_ptr<MessageHandler> MessageHandler::Create( 90 PP_Instance instance, 91 const PPP_MessageHandler_0_2* handler_if, 92 void* user_data, 93 PP_Resource message_loop, 94 int32_t* error) { 95 scoped_ptr<MessageHandler> result; 96 // The interface and all function pointers must be valid. 97 if (!handler_if || 98 !handler_if->HandleMessage || 99 !handler_if->HandleBlockingMessage || 100 !handler_if->Destroy) { 101 *error = PP_ERROR_BADARGUMENT; 102 return result.Pass(); 103 } 104 thunk::EnterResourceNoLock<thunk::PPB_MessageLoop_API> 105 enter_loop(message_loop, true); 106 if (enter_loop.failed()) { 107 *error = PP_ERROR_BADRESOURCE; 108 return result.Pass(); 109 } 110 scoped_refptr<MessageLoopResource> message_loop_resource( 111 static_cast<MessageLoopResource*>(enter_loop.object())); 112 if (message_loop_resource->is_main_thread_loop()) { 113 *error = PP_ERROR_WRONG_THREAD; 114 return result.Pass(); 115 } 116 117 result.reset(new MessageHandler( 118 instance, handler_if, user_data, message_loop_resource)); 119 *error = PP_OK; 120 return result.Pass(); 121 } 122 123 // CreateDeprecated is a near-exact copy of Create, but we'll just delete it 124 // when 0.1 is deprecated, so need to get fancy to avoid code duplication. 125 // TODO(dmichael) crbug.com/414398 126 // static 127 scoped_ptr<MessageHandler> MessageHandler::CreateDeprecated( 128 PP_Instance instance, 129 const PPP_MessageHandler_0_1_Deprecated* handler_if, 130 void* user_data, 131 PP_Resource message_loop, 132 int32_t* error) { 133 scoped_ptr<MessageHandler> result; 134 // The interface and all function pointers must be valid. 135 if (!handler_if || 136 !handler_if->HandleMessage || 137 !handler_if->HandleBlockingMessage || 138 !handler_if->Destroy) { 139 *error = PP_ERROR_BADARGUMENT; 140 return result.Pass(); 141 } 142 thunk::EnterResourceNoLock<thunk::PPB_MessageLoop_API> 143 enter_loop(message_loop, true); 144 if (enter_loop.failed()) { 145 *error = PP_ERROR_BADRESOURCE; 146 return result.Pass(); 147 } 148 scoped_refptr<MessageLoopResource> message_loop_resource( 149 static_cast<MessageLoopResource*>(enter_loop.object())); 150 if (message_loop_resource->is_main_thread_loop()) { 151 *error = PP_ERROR_WRONG_THREAD; 152 return result.Pass(); 153 } 154 155 result.reset(new MessageHandler( 156 instance, handler_if, user_data, message_loop_resource)); 157 *error = PP_OK; 158 return result.Pass(); 159 } 160 161 MessageHandler::~MessageHandler() { 162 // It's possible the message_loop_proxy is NULL if that loop has been quit. 163 // In that case, we unfortunately just can't call Destroy. 164 if (message_loop_->message_loop_proxy().get()) { 165 // The posted task won't have the proxy lock, but that's OK, it doesn't 166 // touch any internal state; it's a direct call on the plugin's function. 167 if (handler_if_0_1_) { 168 message_loop_->message_loop_proxy()->PostTask(FROM_HERE, 169 base::Bind(handler_if_0_1_->Destroy, 170 instance_, 171 user_data_)); 172 return; 173 } 174 message_loop_->message_loop_proxy()->PostTask(FROM_HERE, 175 base::Bind(handler_if_->Destroy, 176 instance_, 177 user_data_)); 178 } 179 } 180 181 bool MessageHandler::LoopIsValid() const { 182 return !!message_loop_->message_loop_proxy().get(); 183 } 184 185 void MessageHandler::HandleMessage(ScopedPPVar var) { 186 if (handler_if_0_1_) { 187 // TODO(dmichael): Remove this code path. crbug.com/414398 188 message_loop_->message_loop_proxy()->PostTask(FROM_HERE, 189 RunWhileLocked(base::Bind(&HandleMessageWrapper_0_1, 190 handler_if_0_1_->HandleMessage, 191 instance_, 192 user_data_, 193 var))); 194 return; 195 } 196 message_loop_->message_loop_proxy()->PostTask(FROM_HERE, 197 RunWhileLocked(base::Bind(&HandleMessageWrapper, 198 handler_if_->HandleMessage, 199 instance_, 200 user_data_, 201 var))); 202 } 203 204 void MessageHandler::HandleBlockingMessage(ScopedPPVar var, 205 scoped_ptr<IPC::Message> reply_msg) { 206 if (handler_if_0_1_) { 207 // TODO(dmichael): Remove this code path. crbug.com/414398 208 message_loop_->message_loop_proxy()->PostTask(FROM_HERE, 209 RunWhileLocked(base::Bind(&HandleBlockingMessageWrapper_0_1, 210 handler_if_0_1_->HandleBlockingMessage, 211 instance_, 212 user_data_, 213 var, 214 base::Passed(reply_msg.Pass())))); 215 return; 216 } 217 message_loop_->message_loop_proxy()->PostTask(FROM_HERE, 218 RunWhileLocked(base::Bind(&HandleBlockingMessageWrapper, 219 handler_if_->HandleBlockingMessage, 220 instance_, 221 user_data_, 222 var, 223 base::Passed(reply_msg.Pass())))); 224 } 225 226 MessageHandler::MessageHandler( 227 PP_Instance instance, 228 const PPP_MessageHandler_0_2* handler_if, 229 void* user_data, 230 scoped_refptr<MessageLoopResource> message_loop) 231 : instance_(instance), 232 handler_if_(handler_if), 233 handler_if_0_1_(NULL), 234 user_data_(user_data), 235 message_loop_(message_loop) { 236 } 237 238 MessageHandler::MessageHandler( 239 PP_Instance instance, 240 const PPP_MessageHandler_0_1_Deprecated* handler_if, 241 void* user_data, 242 scoped_refptr<MessageLoopResource> message_loop) 243 : instance_(instance), 244 handler_if_(NULL), 245 handler_if_0_1_(handler_if), 246 user_data_(user_data), 247 message_loop_(message_loop) { 248 } 249 250 } // namespace proxy 251 } // namespace ppapi 252