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#ifndef PPAPI_PROXY_HOST_DISPATCHER_H_
6#define PPAPI_PROXY_HOST_DISPATCHER_H_
7
8#include <map>
9#include <string>
10#include <vector>
11
12#include "base/compiler_specific.h"
13#include "base/memory/weak_ptr.h"
14#include "base/observer_list.h"
15#include "base/process/process.h"
16#include "ipc/message_filter.h"
17#include "ppapi/c/pp_instance.h"
18#include "ppapi/proxy/dispatcher.h"
19
20struct PPB_Proxy_Private;
21
22namespace ppapi {
23
24struct Preferences;
25
26namespace proxy {
27
28class PPAPI_PROXY_EXPORT HostDispatcher : public Dispatcher {
29 public:
30  // This interface receives notifications about sync messages being sent by
31  // the dispatcher to the plugin process. Some parts of Chrome may need to
32  // know whether we are sending a synchronous message to the plugin; e.g. to
33  // detect a hung plugin or to avoid re-entering JavaScript.
34  //
35  // Note that there can be nested sync messages, so the begin/end status
36  // actually represents a stack of blocking messages.
37  class SyncMessageStatusObserver {
38   public:
39    // Notification that a sync message is about to be sent out.
40    virtual void BeginBlockOnSyncMessage() = 0;
41
42    // Notification that a sync message reply was received and the dispatcher
43    // is no longer blocked on a sync message.
44    virtual void EndBlockOnSyncMessage() = 0;
45
46   protected:
47    virtual ~SyncMessageStatusObserver() {}
48  };
49
50  // Constructor for the renderer side. This will take a reference to the
51  // SyncMessageStatusReceiver.
52  //
53  // You must call InitHostWithChannel after the constructor.
54  HostDispatcher(PP_Module module,
55                 PP_GetInterface_Func local_get_interface,
56                 const PpapiPermissions& permissions);
57  ~HostDispatcher();
58
59  // You must call this function before anything else. Returns true on success.
60  // The delegate pointer must outlive this class, ownership is not
61  // transferred.
62  virtual bool InitHostWithChannel(Delegate* delegate,
63                                   base::ProcessId peer_pid,
64                                   const IPC::ChannelHandle& channel_handle,
65                                   bool is_client,
66                                   const Preferences& preferences);
67
68  // The host side maintains a mapping from PP_Instance to Dispatcher so
69  // that we can send the messages to the right channel.
70  static HostDispatcher* GetForInstance(PP_Instance instance);
71  static void SetForInstance(PP_Instance instance,
72                             HostDispatcher* dispatcher);
73  static void RemoveForInstance(PP_Instance instance);
74
75  // Returns the host's notion of our PP_Module. This will be different than
76  // the plugin's notion of its PP_Module because the plugin process may be
77  // used by multiple renderer processes.
78  //
79  // Use this value instead of a value from the plugin whenever talking to the
80  // host.
81  PP_Module pp_module() const { return pp_module_; }
82
83  // Dispatcher overrides.
84  virtual bool IsPlugin() const;
85  virtual bool Send(IPC::Message* msg);
86
87  // IPC::Listener.
88  virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
89  virtual void OnChannelError() OVERRIDE;
90
91  // Proxied version of calling GetInterface on the plugin. This will check
92  // if the plugin supports the given interface (with caching) and returns the
93  // pointer to the proxied interface if it is supported. Returns NULL if the
94  // given interface isn't supported by the plugin or the proxy.
95  const void* GetProxiedInterface(const std::string& iface_name);
96
97  // See the value below. Call this when processing a scripting message from
98  // the plugin that can be reentered. This is set to false at the beginning
99  // of processing of each message from the plugin.
100  void set_allow_plugin_reentrancy() {
101    allow_plugin_reentrancy_ = true;
102  }
103
104  // Returns the proxy interface for talking to the implementation.
105  const PPB_Proxy_Private* ppb_proxy() const { return ppb_proxy_; }
106
107  // Register an observer that will be invoked when the dispatcher begins
108  // sending a sync message and finishes sending a sync message.
109  // Returns a Closure that can be used to unregister the observer (the Closure
110  // is bound to a weak pointer, so is safe to call even after the
111  // HostDispatcher is gone.)
112  base::Closure AddSyncMessageStatusObserver(SyncMessageStatusObserver* obs);
113
114  void AddFilter(IPC::Listener* listener);
115
116 protected:
117  // Overridden from Dispatcher.
118  virtual void OnInvalidMessageReceived();
119
120 private:
121  void OnHostMsgLogWithSource(PP_Instance instance,
122                              int int_log_level,
123                              const std::string& source,
124                              const std::string& value);
125
126  void RemoveSyncMessageStatusObserver(SyncMessageStatusObserver* obs);
127
128  PP_Module pp_module_;
129
130  // Maps interface name to whether that interface is supported. If an interface
131  // name is not in the map, that implies that we haven't queried for it yet.
132  typedef base::hash_map<std::string, bool> PluginSupportedMap;
133  PluginSupportedMap plugin_supported_;
134
135  // Guaranteed non-NULL.
136  const PPB_Proxy_Private* ppb_proxy_;
137
138  // Set to true when the plugin is in a state that it can be reentered by a
139  // sync message from the host. We allow reentrancy only when we're processing
140  // a sync message from the renderer that is a scripting command. When the
141  // plugin is in this state, it needs to accept reentrancy since scripting may
142  // ultimately call back into the plugin.
143  bool allow_plugin_reentrancy_;
144
145  ObserverList<SyncMessageStatusObserver> sync_status_observer_list_;
146
147  std::vector<IPC::Listener*> filters_;
148
149  base::WeakPtrFactory<HostDispatcher> weak_ptr_factory_;
150
151  DISALLOW_COPY_AND_ASSIGN(HostDispatcher);
152};
153
154// Create this object on the stack to prevent the module (and hence the
155// dispatcher) from being deleted out from under you. This is necessary when
156// calling some scripting functions that may delete the plugin.
157//
158// This class does nothing if used on the plugin side.
159class ScopedModuleReference {
160 public:
161  explicit ScopedModuleReference(Dispatcher* dispatcher);
162  ~ScopedModuleReference();
163
164 private:
165  HostDispatcher* dispatcher_;
166
167  DISALLOW_COPY_AND_ASSIGN(ScopedModuleReference);
168};
169
170}  // namespace proxy
171}  // namespace ppapi
172
173#endif  // PPAPI_PROXY_HOST_DISPATCHER_H_
174