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*, PP_Var);
     20 typedef PP_Var (*HandleBlockingMessageFunc)(PP_Instance, void*, PP_Var);
     21 
     22 void 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 
     29 void 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
     51 scoped_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 
     85 MessageHandler::~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 
     98 bool MessageHandler::LoopIsValid() const {
     99   return !!message_loop_->message_loop_proxy();
    100 }
    101 
    102 void 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 
    111 void 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 
    122 MessageHandler::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