// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PPAPI_PROXY_HOST_DISPATCHER_H_
#define PPAPI_PROXY_HOST_DISPATCHER_H_
#include <map>
#include <string>
#include <unordered_map>
#include <vector>
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/process/process.h"
#include "base/task/single_thread_task_runner.h"
#include "ipc/message_filter.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/proxy/dispatcher.h"
struct PPB_Proxy_Private;
namespace ppapi {
struct Preferences;
namespace proxy {
class PPAPI_PROXY_EXPORT HostDispatcher : public Dispatcher {
public:
// This interface receives notifications about sync messages being sent by
// the dispatcher to the plugin process. Some parts of Chrome may need to
// know whether we are sending a synchronous message to the plugin; e.g. to
// detect a hung plugin or to avoid re-entering JavaScript.
//
// Note that there can be nested sync messages, so the begin/end status
// actually represents a stack of blocking messages.
class SyncMessageStatusObserver {
public:
// Notification that a sync message is about to be sent out.
virtual void BeginBlockOnSyncMessage() = 0;
// Notification that a sync message reply was received and the dispatcher
// is no longer blocked on a sync message.
virtual void EndBlockOnSyncMessage() = 0;
protected:
virtual ~SyncMessageStatusObserver() {}
};
// Constructor for the renderer side. This will take a reference to the
// SyncMessageStatusReceiver.
//
// You must call InitHostWithChannel after the constructor.
HostDispatcher(PP_Module module,
PP_GetInterface_Func local_get_interface,
const PpapiPermissions& permissions);
HostDispatcher(const HostDispatcher&) = delete;
HostDispatcher& operator=(const HostDispatcher&) = delete;
~HostDispatcher();
// You must call this function before anything else. Returns true on success.
// The delegate pointer must outlive this class, ownership is not
// transferred.
virtual bool InitHostWithChannel(
Delegate* delegate,
base::ProcessId peer_pid,
const IPC::ChannelHandle& channel_handle,
bool is_client,
const Preferences& preferences,
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// The host side maintains a mapping from PP_Instance to Dispatcher so
// that we can send the messages to the right channel.
static HostDispatcher* GetForInstance(PP_Instance instance);
static void SetForInstance(PP_Instance instance,
HostDispatcher* dispatcher);
static void RemoveForInstance(PP_Instance instance);
// Returns the host's notion of our PP_Module. This will be different than
// the plugin's notion of its PP_Module because the plugin process may be
// used by multiple renderer processes.
//
// Use this value instead of a value from the plugin whenever talking to the
// host.
PP_Module pp_module() const { return pp_module_; }
// Dispatcher overrides.
bool IsPlugin() const override;
bool Send(IPC::Message* msg) override;
// IPC::Listener.
bool OnMessageReceived(const IPC::Message& msg) override;
void OnChannelError() override;
// Proxied version of calling GetInterface on the plugin. This will check
// if the plugin supports the given interface (with caching) and returns the
// pointer to the proxied interface if it is supported. Returns NULL if the
// given interface isn't supported by the plugin or the proxy.
const void* GetProxiedInterface(const std::string& iface_name);
// See the value below. Call this when processing a scripting message from
// the plugin that can be reentered. This is set to false at the beginning
// of processing of each message from the plugin.
void set_allow_plugin_reentrancy() {
allow_plugin_reentrancy_ = true;
}
// Returns the proxy interface for talking to the implementation.
const PPB_Proxy_Private* ppb_proxy() const { return ppb_proxy_; }
// Register an observer that will be invoked when the dispatcher begins
// sending a sync message and finishes sending a sync message.
// Returns a OnceClosure that can be used to unregister the observer (the
// OnceClosure is bound to a weak pointer, so is safe to call even after the
// HostDispatcher is gone.)
base::OnceClosure AddSyncMessageStatusObserver(
SyncMessageStatusObserver* obs);
void AddFilter(IPC::Listener* listener);
protected:
// Overridden from Dispatcher.
void OnInvalidMessageReceived() override;
private:
void OnHostMsgLogWithSource(PP_Instance instance,
int int_log_level,
const std::string& source,
const std::string& value);
void RemoveSyncMessageStatusObserver(SyncMessageStatusObserver* obs);
PP_Module pp_module_;
// Maps interface name to whether that interface is supported. If an interface
// name is not in the map, that implies that we haven't queried for it yet.
typedef std::unordered_map<std::string, bool> PluginSupportedMap;
PluginSupportedMap plugin_supported_;
// Guaranteed non-NULL.
const PPB_Proxy_Private* ppb_proxy_;
// Set to true when the plugin is in a state that it can be reentered by a
// sync message from the host. We allow reentrancy only when we're processing
// a sync message from the renderer that is a scripting command. When the
// plugin is in this state, it needs to accept reentrancy since scripting may
// ultimately call back into the plugin.
bool allow_plugin_reentrancy_;
base::ObserverList<SyncMessageStatusObserver>::Unchecked
sync_status_observer_list_;
std::vector<IPC::Listener*> filters_;
base::WeakPtrFactory<HostDispatcher> weak_ptr_factory_{this};
};
// Create this object on the stack to prevent the module (and hence the
// dispatcher) from being deleted out from under you. This is necessary when
// calling some scripting functions that may delete the plugin.
//
// This class does nothing if used on the plugin side.
class ScopedModuleReference {
public:
explicit ScopedModuleReference(Dispatcher* dispatcher);
ScopedModuleReference(const ScopedModuleReference&) = delete;
ScopedModuleReference& operator=(const ScopedModuleReference&) = delete;
~ScopedModuleReference();
private:
HostDispatcher* dispatcher_;
};
} // namespace proxy
} // namespace ppapi
#endif // PPAPI_PROXY_HOST_DISPATCHER_H_