Skip to content

Commit

Permalink
Core PPAPI proxy files. This includes the dispatcher which is the con…
Browse files Browse the repository at this point in the history
…trol point

on each end of the IPC channel. It includes the IPC message definitions. It
also includes the base class for the interface proxying, and the core resource
and var tracking.

BUG=none
TEST=none
Review URL: http://codereview.chromium.org/4229002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@64869 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
brettw@chromium.org committed Nov 3, 2010
1 parent 6ed2a5a commit 4bcab1c
Show file tree
Hide file tree
Showing 47 changed files with 6,325 additions and 0 deletions.
72 changes: 72 additions & 0 deletions ppapi/proxy/callback_tracker.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) 2010 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/callback_tracker.h"

#include "ppapi/proxy/dispatcher.h"
#include "ppapi/proxy/ppapi_messages.h"

namespace pp {
namespace proxy {

namespace {

struct CallbackData {
CallbackTracker* tracker;
uint32_t callback_id;
};

void CallbackProxy(void* user_data, int32_t result) {
CallbackData* data = static_cast<CallbackData*>(user_data);
data->tracker->SendExecuteSerializedCallback(data->callback_id, result);
delete data;
}

} // namespace

CallbackTracker::CallbackTracker(Dispatcher* dispatcher)
: dispatcher_(dispatcher),
next_callback_id_(1) {
}

CallbackTracker::~CallbackTracker() {
}

uint32_t CallbackTracker::SendCallback(PP_CompletionCallback callback) {
// Find the next callback ID we can use (being careful about wraparound).
while (callback_map_.find(next_callback_id_) != callback_map_.end())
next_callback_id_++;
callback_map_[next_callback_id_] = callback;
return next_callback_id_++;
}

PP_CompletionCallback CallbackTracker::ReceiveCallback(
uint32_t serialized_callback) {
CallbackData* data = new CallbackData;
data->tracker = this;
data->callback_id = serialized_callback;
return PP_MakeCompletionCallback(&CallbackProxy, data);
}

void CallbackTracker::SendExecuteSerializedCallback(
uint32_t serialized_callback,
int32_t param) {
dispatcher_->Send(new PpapiMsg_ExecuteCallback(serialized_callback, param));
}

void CallbackTracker::ReceiveExecuteSerializedCallback(
uint32_t serialized_callback,
int32_t param) {
CallbackMap::iterator found = callback_map_.find(serialized_callback);
if (found == callback_map_.end()) {
NOTREACHED();
return;
}

PP_RunCompletionCallback(&found->second, param);
callback_map_.erase(found);
}

} // namespace proxy
} // namespace pp
66 changes: 66 additions & 0 deletions ppapi/proxy/callback_tracker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) 2010 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.

#ifndef PPAPI_PROXY_CALLBACK_TRACKER_H_
#define PPAPI_PROXY_CALLBACK_TRACKER_H_

#include <map>

#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_stdint.h"

namespace pp {
namespace proxy {

class Dispatcher;

// This object tracks cross-process callbacks. When the plugin sends a callback
// object to the renderer, we save the information and pass an identifier
// instead.
//
// On the renderer side, this identifier is converted to a new callback in that
// process. When executed, this new callback sends an IPC message containing the
// previous identifier back to the plugin.
//
// When we receive that message, ExecuteSerializedCallback converts the
// identifier back to the original callback information and runs the callback.
class CallbackTracker {
public:
CallbackTracker(Dispatcher* dispatcher);
~CallbackTracker();

// Converts the given callback in the context of the plugin to a serialized
// ID. This will be passed to ReceiveCallback on the renderer side.
uint32_t SendCallback(PP_CompletionCallback callback);

// Converts the given serialized callback ID to a new completion callback in
// the context of the current process. This callback actually will represent
// a proxy that will execute the callback in the plugin process.
PP_CompletionCallback ReceiveCallback(uint32_t serialized_callback);

// Sends a request to the remote process to execute the given callback.
void SendExecuteSerializedCallback(uint32_t serialized_callback,
int32_t param);

// Executes the given callback ID with the given result in the current
// process. This will also destroy the information associated with the
// callback and the serialized ID won't be valid any more.
void ReceiveExecuteSerializedCallback(uint32_t serialized_callback,
int32_t param);

private:
// Pointer to the dispatcher that owns us.
Dispatcher* dispatcher_;

int32_t next_callback_id_;

// Maps callback IDs to the actual callback objects in the plugin process.
typedef std::map<int32_t, PP_CompletionCallback> CallbackMap;
CallbackMap callback_map_;
};

} // namespace proxy
} // namespace pp

#endif // PPAPI_PROXY_CALLBACK_TRACKER_H_
215 changes: 215 additions & 0 deletions ppapi/proxy/dispatcher.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
// Copyright (c) 2010 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/dispatcher.h"

#include <string.h> // For memset.

#include <map>

#include "base/logging.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_sync_channel.h"
#include "ppapi/proxy/interface_proxy.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/c/dev/ppb_var_deprecated.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/ppb_core.h"
#include "ppapi/c/ppb_graphics_2d.h"
#include "ppapi/c/ppb_image_data.h"
#include "ppapi/c/ppb_instance.h"
#include "ppapi/c/ppp_instance.h"
#include "ppapi/proxy/ppb_core_proxy.h"
#include "ppapi/proxy/ppb_graphics_2d_proxy.h"
#include "ppapi/proxy/ppb_image_data_proxy.h"
#include "ppapi/proxy/ppb_instance_proxy.h"
#include "ppapi/proxy/ppb_var_deprecated_proxy.h"
#include "ppapi/proxy/ppp_class_proxy.h"
#include "ppapi/proxy/ppp_instance_proxy.h"
#include "ppapi/proxy/var_serialization_rules.h"

namespace pp {
namespace proxy {

Dispatcher::Dispatcher(GetInterfaceFunc local_get_interface)
: pp_module_(0),
disallow_trusted_interfaces_(true),
local_get_interface_(local_get_interface),
declared_supported_remote_interfaces_(false),
callback_tracker_(this) {
memset(id_to_proxy_, 0,
static_cast<int>(INTERFACE_ID_COUNT) * sizeof(InterfaceProxy*));
}

Dispatcher::~Dispatcher() {
}

bool Dispatcher::InitWithChannel(MessageLoop* ipc_message_loop,
const std::string& channel_name,
bool is_client,
base::WaitableEvent* shutdown_event) {
IPC::Channel::Mode mode = is_client ? IPC::Channel::MODE_CLIENT
: IPC::Channel::MODE_SERVER;
channel_.reset(new IPC::SyncChannel(channel_name, mode, this, NULL,
ipc_message_loop, false, shutdown_event));
return true;
}

void Dispatcher::OnMessageReceived(const IPC::Message& msg) {
// Control messages.
if (msg.routing_id() == MSG_ROUTING_CONTROL) {
IPC_BEGIN_MESSAGE_MAP(Dispatcher, msg)
IPC_MESSAGE_HANDLER(PpapiMsg_DeclareInterfaces,
OnMsgDeclareInterfaces)
IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface)
IPC_MESSAGE_FORWARD(PpapiMsg_ExecuteCallback, &callback_tracker_,
CallbackTracker::ReceiveExecuteSerializedCallback)
IPC_END_MESSAGE_MAP()
return;
}

// Interface-specific messages.
if (msg.routing_id() > 0 && msg.routing_id() < INTERFACE_ID_COUNT) {
InterfaceProxy* proxy = id_to_proxy_[msg.routing_id()];
if (proxy)
proxy->OnMessageReceived(msg);
else
NOTREACHED();
// TODO(brettw): kill the plugin if it starts sending invalid messages?
}
}

void Dispatcher::SetSerializationRules(
VarSerializationRules* var_serialization_rules) {
serialization_rules_.reset(var_serialization_rules);
}

void Dispatcher::InjectProxy(InterfaceID id,
const std::string& name,
InterfaceProxy* proxy) {
proxies_[name] = linked_ptr<InterfaceProxy>(proxy);
id_to_proxy_[id] = proxy;
}

const void* Dispatcher::GetLocalInterface(const char* interface) {
return local_get_interface_(interface);
}

const void* Dispatcher::GetProxiedInterface(const std::string& interface) {
// See if we already know about this interface and have created a host.
ProxyMap::const_iterator found = proxies_.find(interface);
if (found != proxies_.end())
return found->second->GetSourceInterface();

// When the remote side has sent us a declared list of all interfaces it
// supports and we don't have it in our list, we know the requested interface
// doesn't exist and we can return failure.
if (declared_supported_remote_interfaces_)
return NULL;

if (!RemoteSupportsTargetInterface(interface))
return NULL;

linked_ptr<InterfaceProxy> proxy(CreateProxyForInterface(interface, NULL));
if (!proxy.get())
return NULL; // Don't know how to proxy this interface.

// Save our proxy.
proxies_[interface] = proxy;
id_to_proxy_[proxy->GetInterfaceId()] = proxy.get();
return proxy->GetSourceInterface();
}

bool Dispatcher::Send(IPC::Message* msg) {
return channel_->Send(msg);
}

bool Dispatcher::RemoteSupportsTargetInterface(const std::string& interface) {
bool result = false;
Send(new PpapiMsg_SupportsInterface(interface, &result));
return result;
}

bool Dispatcher::IsInterfaceTrusted(const std::string& interface) {
// FIXME(brettw)
(void)interface;
return false;
}

bool Dispatcher::SetupProxyForTargetInterface(const std::string& interface) {
// If we already have a proxy that knows about the locally-implemented
// interface, we know it's supported and don't need to re-query.
ProxyMap::const_iterator found = proxies_.find(interface);
if (found != proxies_.end())
return true;

if (disallow_trusted_interfaces_ && IsInterfaceTrusted(interface))
return false;

// Create the proxy if it doesn't exist and set the local interface on it.
// This also handles the case where possibly an interface could be supported
// by both the local and remote side.
const void* interface_functions = local_get_interface_(interface.c_str());
if (!interface_functions)
return false;
InterfaceProxy* proxy = CreateProxyForInterface(interface,
interface_functions);
if (!proxy)
return false;

proxies_[interface] = linked_ptr<InterfaceProxy>(proxy);
id_to_proxy_[proxy->GetInterfaceId()] = proxy;
return true;
}

void Dispatcher::OnMsgSupportsInterface(const std::string& interface_name,
bool* result) {
*result = SetupProxyForTargetInterface(interface_name);
}

void Dispatcher::OnMsgDeclareInterfaces(
const std::vector<std::string>& interfaces) {
// Make proxies for all the interfaces it supports that we also support.
for (size_t i = 0; i < interfaces.size(); i++) {
// Possibly the plugin could request an interface before the "declare"
// message is received, so we could already have an entry for this
// interface. In this case, we can just skip to the next one.
if (proxies_.find(interfaces[i]) != proxies_.end())
continue;

linked_ptr<InterfaceProxy> proxy(CreateProxyForInterface(interfaces[i],
NULL));
if (!proxy.get()) {
// Since only the browser declares supported interfaces, we should never
// get one we don't support.
//NOTREACHED() << "Remote side declaring an unsupported proxy.";
continue;
}
proxies_[interfaces[i]] = proxy;
id_to_proxy_[proxy->GetInterfaceId()] = proxy.get();
}
}

InterfaceProxy* Dispatcher::CreateProxyForInterface(
const std::string& interface_name,
const void* interface_functions) {
if (interface_name == PPB_CORE_INTERFACE)
return new PPB_Core_Proxy(this, interface_functions);
if (interface_name == PPB_GRAPHICS_2D_INTERFACE)
return new PPB_Graphics2D_Proxy(this, interface_functions);
if (interface_name == PPB_IMAGEDATA_INTERFACE)
return new PPB_ImageData_Proxy(this, interface_functions);
if (interface_name == PPB_INSTANCE_INTERFACE)
return new PPB_Instance_Proxy(this, interface_functions);
if (interface_name == PPB_VAR_DEPRECATED_INTERFACE)
return new PPB_Var_Deprecated_Proxy(this, interface_functions);
if (interface_name == PPP_INSTANCE_INTERFACE)
return new PPP_Instance_Proxy(this, interface_functions);

return NULL;
}

} // namespace proxy
} // namespace pp

Loading

0 comments on commit 4bcab1c

Please sign in to comment.