Home | History | Annotate | Download | only in proxy
      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