// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ppapi/proxy/message_handler.h" #include #include "base/location.h" #include "base/single_thread_task_runner.h" #include "ipc/ipc_message.h" #include "ppapi/proxy/plugin_dispatcher.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/ppb_message_loop_proxy.h" #include "ppapi/shared_impl/proxy_lock.h" #include "ppapi/shared_impl/scoped_pp_var.h" #include "ppapi/thunk/enter.h" namespace ppapi { namespace proxy { namespace { typedef void (*HandleMessageFunc)(PP_Instance, void*, const PP_Var*); typedef void (*HandleBlockingMessageFunc)( PP_Instance, void*, const PP_Var*, PP_Var*); void HandleMessageWrapper(HandleMessageFunc function, PP_Instance instance, void* user_data, ScopedPPVar message_data) { CallWhileUnlocked(function, instance, user_data, &message_data.get()); } void HandleBlockingMessageWrapper(HandleBlockingMessageFunc function, PP_Instance instance, void* user_data, ScopedPPVar message_data, scoped_ptr reply_msg) { PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); if (!dispatcher) return; PP_Var result = PP_MakeUndefined(); MessageLoopResource::GetCurrent()-> set_currently_handling_blocking_message(true); CallWhileUnlocked( function, instance, user_data, &message_data.get(), &result); MessageLoopResource::GetCurrent()-> set_currently_handling_blocking_message(false); PpapiMsg_PPPMessageHandler_HandleBlockingMessage::WriteReplyParams( reply_msg.get(), SerializedVarReturnValue::Convert(dispatcher, result), true /* was_handled */); dispatcher->Send(reply_msg.release()); } } // namespace // static scoped_ptr MessageHandler::Create( PP_Instance instance, const PPP_MessageHandler_0_2* handler_if, void* user_data, PP_Resource message_loop, int32_t* error) { scoped_ptr result; // The interface and all function pointers must be valid. if (!handler_if || !handler_if->HandleMessage || !handler_if->HandleBlockingMessage || !handler_if->Destroy) { *error = PP_ERROR_BADARGUMENT; return result; } thunk::EnterResourceNoLock enter_loop(message_loop, true); if (enter_loop.failed()) { *error = PP_ERROR_BADRESOURCE; return result; } scoped_refptr message_loop_resource( static_cast(enter_loop.object())); if (message_loop_resource->is_main_thread_loop()) { *error = PP_ERROR_WRONG_THREAD; return result; } result.reset(new MessageHandler( instance, handler_if, user_data, message_loop_resource)); *error = PP_OK; return result; } MessageHandler::~MessageHandler() { // It's possible the message_loop_proxy is NULL if that loop has been quit. // In that case, we unfortunately just can't call Destroy. if (message_loop_->task_runner().get()) { // The posted task won't have the proxy lock, but that's OK, it doesn't // touch any internal state; it's a direct call on the plugin's function. message_loop_->task_runner()->PostTask( FROM_HERE, base::Bind(handler_if_->Destroy, instance_, user_data_)); } } bool MessageHandler::LoopIsValid() const { return !!message_loop_->task_runner().get(); } void MessageHandler::HandleMessage(ScopedPPVar var) { message_loop_->task_runner()->PostTask( FROM_HERE, RunWhileLocked(base::Bind(&HandleMessageWrapper, handler_if_->HandleMessage, instance_, user_data_, var))); } void MessageHandler::HandleBlockingMessage(ScopedPPVar var, scoped_ptr reply_msg) { message_loop_->task_runner()->PostTask( FROM_HERE, RunWhileLocked(base::Bind( &HandleBlockingMessageWrapper, handler_if_->HandleBlockingMessage, instance_, user_data_, var, base::Passed(std::move(reply_msg))))); } MessageHandler::MessageHandler( PP_Instance instance, const PPP_MessageHandler_0_2* handler_if, void* user_data, scoped_refptr message_loop) : instance_(instance), handler_if_(handler_if), user_data_(user_data), message_loop_(message_loop) { } } // namespace proxy } // namespace ppapi