• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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/ppp_messaging_proxy.h"
6 
7 #include <algorithm>
8 
9 #include "ppapi/c/ppp_messaging.h"
10 #include "ppapi/proxy/host_dispatcher.h"
11 #include "ppapi/proxy/message_handler.h"
12 #include "ppapi/proxy/plugin_dispatcher.h"
13 #include "ppapi/proxy/plugin_resource_tracker.h"
14 #include "ppapi/proxy/plugin_var_tracker.h"
15 #include "ppapi/proxy/ppapi_messages.h"
16 #include "ppapi/proxy/serialized_var.h"
17 #include "ppapi/shared_impl/ppapi_globals.h"
18 #include "ppapi/shared_impl/proxy_lock.h"
19 #include "ppapi/shared_impl/scoped_pp_var.h"
20 #include "ppapi/shared_impl/var_tracker.h"
21 
22 namespace ppapi {
23 namespace proxy {
24 
25 namespace {
26 
GetMessageHandler(Dispatcher * dispatcher,PP_Instance instance)27 MessageHandler* GetMessageHandler(Dispatcher* dispatcher,
28                                   PP_Instance instance) {
29   if (!dispatcher || !dispatcher->IsPlugin()) {
30     NOTREACHED();
31     return NULL;
32   }
33   PluginDispatcher* plugin_dispatcher =
34       static_cast<PluginDispatcher*>(dispatcher);
35   InstanceData* instance_data = plugin_dispatcher->GetInstanceData(instance);
36   if (!instance_data)
37     return NULL;
38 
39   return instance_data->message_handler.get();
40 }
41 
ResetMessageHandler(Dispatcher * dispatcher,PP_Instance instance)42 void ResetMessageHandler(Dispatcher* dispatcher, PP_Instance instance) {
43   if (!dispatcher || !dispatcher->IsPlugin()) {
44     NOTREACHED();
45     return;
46   }
47   PluginDispatcher* plugin_dispatcher =
48       static_cast<PluginDispatcher*>(dispatcher);
49   InstanceData* instance_data = plugin_dispatcher->GetInstanceData(instance);
50   if (!instance_data)
51     return;
52 
53   instance_data->message_handler.reset();
54 }
55 
56 }  // namespace
57 
PPP_Messaging_Proxy(Dispatcher * dispatcher)58 PPP_Messaging_Proxy::PPP_Messaging_Proxy(Dispatcher* dispatcher)
59     : InterfaceProxy(dispatcher),
60       ppp_messaging_impl_(NULL) {
61   if (dispatcher->IsPlugin()) {
62     ppp_messaging_impl_ = static_cast<const PPP_Messaging*>(
63         dispatcher->local_get_interface()(PPP_MESSAGING_INTERFACE));
64   }
65 }
66 
~PPP_Messaging_Proxy()67 PPP_Messaging_Proxy::~PPP_Messaging_Proxy() {
68 }
69 
OnMessageReceived(const IPC::Message & msg)70 bool PPP_Messaging_Proxy::OnMessageReceived(const IPC::Message& msg) {
71   if (!dispatcher()->IsPlugin())
72     return false;
73 
74   bool handled = true;
75   IPC_BEGIN_MESSAGE_MAP(PPP_Messaging_Proxy, msg)
76     IPC_MESSAGE_HANDLER(PpapiMsg_PPPMessaging_HandleMessage,
77                         OnMsgHandleMessage)
78     IPC_MESSAGE_HANDLER_DELAY_REPLY(
79         PpapiMsg_PPPMessageHandler_HandleBlockingMessage,
80         OnMsgHandleBlockingMessage)
81     IPC_MESSAGE_UNHANDLED(handled = false)
82   IPC_END_MESSAGE_MAP()
83   return handled;
84 }
85 
OnMsgHandleMessage(PP_Instance instance,SerializedVarReceiveInput message_data)86 void PPP_Messaging_Proxy::OnMsgHandleMessage(
87     PP_Instance instance, SerializedVarReceiveInput message_data) {
88   PP_Var received_var(message_data.GetForInstance(dispatcher(), instance));
89   MessageHandler* message_handler = GetMessageHandler(dispatcher(), instance);
90   if (message_handler) {
91     if (message_handler->LoopIsValid()) {
92       message_handler->HandleMessage(ScopedPPVar(received_var));
93       return;
94     } else {
95       // If the MessageHandler's loop has been quit, then we should treat it as
96       // though it has been unregistered and start sending messages to the
97       // default handler. This might mean the plugin has lost messages, but
98       // there's not really anything sane we can do about it. They should have
99       // used UnregisterMessageHandler.
100       ResetMessageHandler(dispatcher(), instance);
101     }
102   }
103   // If we reach this point, then there's no message handler registered, so
104   // we send to the default PPP_Messaging one for the instance.
105 
106   // SerializedVarReceiveInput will decrement the reference count, but we want
107   // to give the recipient a reference in the legacy API.
108   PpapiGlobals::Get()->GetVarTracker()->AddRefVar(received_var);
109   CallWhileUnlocked(ppp_messaging_impl_->HandleMessage,
110                     instance,
111                     received_var);
112 }
113 
OnMsgHandleBlockingMessage(PP_Instance instance,SerializedVarReceiveInput message_data,IPC::Message * reply_msg)114 void PPP_Messaging_Proxy::OnMsgHandleBlockingMessage(
115     PP_Instance instance,
116     SerializedVarReceiveInput message_data,
117     IPC::Message* reply_msg) {
118   ScopedPPVar received_var(message_data.GetForInstance(dispatcher(), instance));
119   MessageHandler* message_handler = GetMessageHandler(dispatcher(), instance);
120   if (message_handler) {
121     if (message_handler->LoopIsValid()) {
122       message_handler->HandleBlockingMessage(
123           received_var, scoped_ptr<IPC::Message>(reply_msg));
124       return;
125     } else {
126       // If the MessageHandler's loop has been quit, then we should treat it as
127       // though it has been unregistered. Also see the note for PostMessage.
128       ResetMessageHandler(dispatcher(), instance);
129     }
130   }
131   // We have no handler, but we still need to respond to unblock the renderer
132   // and inform the JavaScript caller.
133   PpapiMsg_PPPMessageHandler_HandleBlockingMessage::WriteReplyParams(
134       reply_msg,
135       SerializedVarReturnValue::Convert(dispatcher(), PP_MakeUndefined()),
136       false /* was_handled */);
137   dispatcher()->Send(reply_msg);
138 }
139 
140 
141 }  // namespace proxy
142 }  // namespace ppapi
143