Skip to content

Commit

Permalink
PPAPI/NaCl: Make NaClIPCAdapter transfer handles more generally
Browse files Browse the repository at this point in the history
This does a couple of things:
- It defines a new wrapper for passing any kind of handle through the PPAPI proxy (SerializedHandle).
- It updates nacl_ipc_adapter to have a more general way to pick apart messages based on their static types (which include the types of all the params).
- It adds support for PPB_Graphics2D and PPB_Graphics3D to the NaCl IPC proxy (e.g., NaCl SDK examples pi_generator and tumbler work in the new proxy with this patch).

The downside is it requires pulling parts of ppapi/shared_impl and ppapi/proxy in to the NaCl Win64 build. 

BUG=116317
TEST=


Review URL: https://chromiumcodereview.appspot.com/10828023

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@153531 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
dmichael@chromium.org committed Aug 27, 2012
1 parent 906960b commit 246fc49
Show file tree
Hide file tree
Showing 51 changed files with 973 additions and 246 deletions.
2 changes: 1 addition & 1 deletion chrome/chrome_browser.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
'../crypto/crypto.gyp:crypto',
'../media/media.gyp:media',
'../net/net.gyp:net',
'../ppapi/ppapi_internal.gyp:ppapi_proxy', # For PpapiMsg_LoadPlugin
'../ppapi/ppapi_internal.gyp:ppapi_ipc', # For PpapiMsg_LoadPlugin
'../printing/printing.gyp:printing',
'../skia/skia.gyp:skia',
'../sync/protocol/sync_proto.gyp:sync_proto',
Expand Down
1 change: 1 addition & 0 deletions chrome/chrome_renderer.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
'../net/net.gyp:net',
'../ppapi/ppapi_internal.gyp:ppapi_host',
'../ppapi/ppapi_internal.gyp:ppapi_proxy',
'../ppapi/ppapi_internal.gyp:ppapi_ipc',
'../ppapi/ppapi_internal.gyp:ppapi_shared',
'../printing/printing.gyp:printing',
'../skia/skia.gyp:skia',
Expand Down
7 changes: 7 additions & 0 deletions chrome/nacl.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@
'../base/base.gyp:base',
'../ipc/ipc.gyp:ipc',
'../ppapi/native_client/src/trusted/plugin/plugin.gyp:ppGoogleNaClPluginChrome',
'../ppapi/ppapi_internal.gyp:ppapi_shared',
'../ppapi/ppapi_internal.gyp:ppapi_ipc',
'../native_client/src/trusted/service_runtime/service_runtime.gyp:sel',
'../native_client/src/trusted/platform_qualify/platform_qualify.gyp:platform_qual_lib',
],
Expand Down Expand Up @@ -103,6 +105,11 @@
'dependencies': [
'../native_client/src/trusted/service_runtime/service_runtime.gyp:sel64',
'../native_client/src/trusted/platform_qualify/platform_qualify.gyp:platform_qual_lib64',
'../ppapi/ppapi_internal.gyp:ppapi_shared_win64',
'../ppapi/ppapi_internal.gyp:ppapi_ipc_win64',
],
'export_dependent_settings': [
'../ppapi/ppapi_internal.gyp:ppapi_ipc_win64',
],
'sources': [
'common/nacl_cmd_line.cc',
Expand Down
269 changes: 192 additions & 77 deletions chrome/nacl/nacl_ipc_adapter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,45 +89,109 @@ void DeleteChannel(IPC::Channel* channel) {
delete channel;
}

bool ReadHostResource(PickleIterator* it, int* instance_id, int* resource_id) {
return it->ReadInt(instance_id) &&
it->ReadInt(resource_id);
}

bool ReadFileDescriptor(const IPC::Message& message,
PickleIterator* it,
NaClHandle* handle) {
#if defined(OS_POSIX)
bool valid;
base::FileDescriptor desc;
if (!it->ReadBool(&valid) ||
!valid ||
!message.ReadFileDescriptor(it, &desc))
return false;

*handle = desc.fd;
return true;
#else
uint32 value;
if (!it->ReadUInt32(&value))
return false;
void WriteFileDescriptor(int handle_index,
const ppapi::proxy::SerializedHandle& handle,
IPC::Message* message) {
ppapi::proxy::SerializedHandle::WriteHeader(handle.header(), message);

*handle = reinterpret_cast<NaClHandle>(value);
return true;
#endif // defined(OS_POSIX)
}
// Now write the handle itself in POSIX style.
message->WriteBool(true); // valid == true
message->WriteInt(handle_index);
}

typedef std::vector<ppapi::proxy::SerializedHandle> Handles;

// We define one overload for catching SerializedHandles, so that we can share
// them correctly to the untrusted side, and another for handling all other
// parameters. See ConvertHandlesImpl for how these get used.
void ConvertHandle(const ppapi::proxy::SerializedHandle& handle,
Handles* handles, IPC::Message* msg, int* handle_index) {
handles->push_back(handle);
if (msg)
WriteFileDescriptor((*handle_index)++, handle, msg);
}

// This overload is to catch all types other than SerializedHandle. On Windows,
// |msg| will be a valid pointer, and we must write |param| to it
template <class T>
void ConvertHandle(const T& param, Handles* /* handles */, IPC::Message* msg,
int* /* handle_index */) {
// It's not a handle, so just write to the output message, if necessary.
if (msg)
IPC::WriteParam(msg, param);
}

// These just break apart the given tuple and run ConvertHandle over each param.
// The idea is to extract any handles in the tuple, while writing all data to
// msg (if msg is valid). The msg will only be valid on Windows, where we need
// to re-write all of the message parameters, writing the handles in POSIX style
// for NaCl.
template <class A>
void ConvertHandlesImpl(const Tuple1<A>& t1, Handles* handles,
IPC::Message* msg) {
int handle_index = 0;
ConvertHandle(t1.a, handles, msg, &handle_index);
}
template <class A, class B>
void ConvertHandlesImpl(const Tuple2<A, B>& t1, Handles* handles,
IPC::Message* msg) {
int handle_index = 0;
ConvertHandle(t1.a, handles, msg, &handle_index);
ConvertHandle(t1.b, handles, msg, &handle_index);
}
template <class A, class B, class C>
void ConvertHandlesImpl(const Tuple3<A, B, C>& t1, Handles* handles,
IPC::Message* msg) {
int handle_index = 0;
ConvertHandle(t1.a, handles, msg, &handle_index);
ConvertHandle(t1.b, handles, msg, &handle_index);
ConvertHandle(t1.c, handles, msg, &handle_index);
}
template <class A, class B, class C, class D>
void ConvertHandlesImpl(const Tuple4<A, B, C, D>& t1, Handles* handles,
IPC::Message* msg) {
int handle_index = 0;
ConvertHandle(t1.a, handles, msg, &handle_index);
ConvertHandle(t1.b, handles, msg, &handle_index);
ConvertHandle(t1.c, handles, msg, &handle_index);
ConvertHandle(t1.d, handles, msg, &handle_index);
}

template <class MessageType>
class HandleConverter {
public:
explicit HandleConverter(const IPC::Message* msg)
: msg_(static_cast<const MessageType*>(msg)) {
}
bool ConvertMessage(Handles* handles, IPC::Message* out_msg) {
typename TupleTypes<typename MessageType::Schema::Param>::ValueTuple params;
if (!MessageType::Read(msg_, &params))
return false;
ConvertHandlesImpl(params, handles, out_msg);
return true;
}

void WriteHostResource(IPC::Message* message,
int instance_id,
int resource_id) {
message->WriteInt(instance_id);
message->WriteInt(resource_id);
}
bool ConvertReply(Handles* handles, IPC::SyncMessage* out_msg) {
typename TupleTypes<typename MessageType::Schema::ReplyParam>::ValueTuple
params;
if (!MessageType::ReadReplyParam(msg_, &params))
return false;
out_msg->set_reply();
// If we need to rewrite the message (i.e., on Windows), we need to make
// sure we write the message id first.
if (out_msg) {
int id = IPC::SyncMessage::GetMessageId(*msg_);
out_msg->WriteInt(id);
}
ConvertHandlesImpl(params, handles, out_msg);
return true;
}
// TODO(dmichael): Add ConvertSyncMessage for outgoing sync messages, if we
// ever pass handles in one of those.

void WriteFileDescriptor(IPC::Message* message, int index) {
message->WriteBool(true); // valid == true
message->WriteInt(index);
}
private:
const MessageType* msg_;
};

} // namespace

Expand Down Expand Up @@ -354,59 +418,104 @@ int NaClIPCAdapter::TakeClientFileDescriptor() {
}
#endif

#define CASE_FOR_MESSAGE(MESSAGE_TYPE) \
case MESSAGE_TYPE::ID: { \
HandleConverter<MESSAGE_TYPE> extractor(&msg); \
if (!extractor.ConvertMessage(&handles, new_msg_ptr)) \
return false; \
break; \
}
#define CASE_FOR_REPLY(MESSAGE_TYPE) \
case MESSAGE_TYPE::ID: { \
HandleConverter<MESSAGE_TYPE> extractor(&msg); \
if (!extractor.ConvertReply( \
&handles, \
static_cast<IPC::SyncMessage*>(new_msg_ptr))) \
return false; \
break; \
}
bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& msg) {
{
base::AutoLock lock(lock_);

scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage);

PickleIterator it(msg);
switch (msg.type()) {
case PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID: {
int instance_id;
int resource_id;
int result_code;
NaClHandle sock_handle;
NaClHandle shm_handle;
uint32_t shm_length;
if (ReadHostResource(&it, &instance_id, &resource_id) &&
it.ReadInt(&result_code) &&
ReadFileDescriptor(msg, &it, &sock_handle) &&
ReadFileDescriptor(msg, &it, &shm_handle) &&
it.ReadUInt32(&shm_length)) {
// Import the sync socket.
nacl::DescWrapperFactory factory;
scoped_ptr<nacl::DescWrapper> socket_wrapper(
factory.ImportSyncSocketHandle(sock_handle));
// Import the shared memory handle and increase its size by 4 bytes to
// accommodate the length data we write at the end to signal the host.
scoped_ptr<nacl::DescWrapper> shm_wrapper(
factory.ImportShmHandle(shm_handle, shm_length + sizeof(uint32)));
if (shm_wrapper.get() && socket_wrapper.get()) {
rewritten_msg->AddDescriptor(socket_wrapper.release());
rewritten_msg->AddDescriptor(shm_wrapper.release());
}
#if defined(OS_POSIX)
SaveMessage(msg, rewritten_msg.get());
#else
// On Windows we must rewrite the message to match the POSIX form.
IPC::Message new_msg(msg.routing_id(),
PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID,
msg.priority());
WriteHostResource(&new_msg, instance_id, resource_id);
new_msg.WriteInt(result_code);
WriteFileDescriptor(&new_msg, 0); // socket handle, index = 0
WriteFileDescriptor(&new_msg, 1); // shm handle, index = 1
new_msg.WriteUInt32(shm_length);
SaveMessage(new_msg, rewritten_msg.get());
// Pointer to the "new" message we will rewrite on Windows. On posix, this
// isn't necessary, so it will stay NULL.
IPC::Message* new_msg_ptr = NULL;
#if defined(OS_WIN)
IPC::Message new_msg(msg.routing_id(), msg.type(), msg.priority());
new_msg_ptr = &new_msg;
#endif
Handles handles;
switch (msg.type()) {
CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated)
CASE_FOR_MESSAGE(PpapiMsg_PPBAudioInput_OpenACK)
case IPC_REPLY_ID: {
int id = IPC::SyncMessage::GetMessageId(msg);
LockedData::PendingSyncMsgMap::iterator iter(
locked_data_.pending_sync_msgs_.find(id));
if (iter == locked_data_.pending_sync_msgs_.end()) {
NOTREACHED();
return false;
}
uint32_t type = iter->second;
locked_data_.pending_sync_msgs_.erase(iter);
switch (type) {
CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer)
CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateNaCl)
default:
// Do nothing for messages we don't know.
break;
}
break;
}
default: {
SaveMessage(msg, rewritten_msg.get());
default:
// Do nothing for messages we don't know.
break;
}
// Now add any descriptors we found to rewritten_msg. |handles| is usually
// empty, unless we read a message containing a FD or handle.
nacl::DescWrapperFactory factory;
for (Handles::const_iterator iter = handles.begin();
iter != handles.end();
++iter) {
scoped_ptr<nacl::DescWrapper> nacl_desc;
switch (iter->type()) {
case ppapi::proxy::SerializedHandle::SHARED_MEMORY: {
const base::SharedMemoryHandle& shm_handle = iter->shmem();
uint32_t size = iter->size();
nacl_desc.reset(factory.ImportShmHandle(
#if defined(OS_WIN)
reinterpret_cast<const NaClHandle>(shm_handle),
#else
shm_handle.fd,
#endif
static_cast<size_t>(size)));
break;
}
case ppapi::proxy::SerializedHandle::SOCKET: {
nacl_desc.reset(factory.ImportSyncSocketHandle(
#if defined(OS_WIN)
reinterpret_cast<const NaClHandle>(iter->descriptor())
#else
iter->descriptor().fd
#endif
));
}
case ppapi::proxy::SerializedHandle::INVALID: {
// Nothing to do. TODO(dmichael): Should we log this? Or is it
// sometimes okay to pass an INVALID handle?
}
// No default, so the compiler will warn us if new types get added.
}
if (nacl_desc.get())
rewritten_msg->AddDescriptor(nacl_desc.release());
}
if (new_msg_ptr && !handles.empty())
SaveMessage(*new_msg_ptr, rewritten_msg.get());
else
SaveMessage(msg, rewritten_msg.get());
}
cond_var_.Signal();
return true;
Expand Down Expand Up @@ -480,6 +589,12 @@ bool NaClIPCAdapter::SendCompleteMessage(const char* buffer,
if (locked_data_.channel_closed_)
return false; // TODO(brettw) clean up handles here when we add support!

// Store the type of all sync messages so that later we can translate the
// reply if necessary.
if (msg->is_sync()) {
int id = IPC::SyncMessage::GetMessageId(*msg);
locked_data_.pending_sync_msgs_[id] = msg->type();
}
// Actual send must be done on the I/O thread.
task_runner_->PostTask(FROM_HERE,
base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this,
Expand Down
7 changes: 7 additions & 0 deletions chrome/nacl/nacl_ipc_adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef CHROME_NACL_NACL_IPC_ADAPTER_H_
#define CHROME_NACL_NACL_IPC_ADAPTER_H_

#include <map>
#include <queue>
#include <string>

Expand Down Expand Up @@ -117,6 +118,12 @@ class NaClIPCAdapter : public base::RefCountedThreadSafe<NaClIPCAdapter>,
// to be received by the plugin.
std::queue< scoped_refptr<RewrittenMessage> > to_be_received_;

// When we send a synchronous message (from untrusted to trusted), we store
// its type here, so that later we can associate the reply with its type
// and potentially translate handles in the message.
typedef std::map<int, uint32> PendingSyncMsgMap;
PendingSyncMsgMap pending_sync_msgs_;

// Data that we've queued from the plugin to send, but doesn't consist of a
// full message yet. The calling code can break apart the message into
// smaller pieces, and we need to send the message to the other process in
Expand Down
2 changes: 1 addition & 1 deletion content/content_browser.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'../crypto/crypto.gyp:crypto',
'../net/net.gyp:http_server',
'../net/net.gyp:net',
'../ppapi/ppapi_internal.gyp:ppapi_proxy',
'../ppapi/ppapi_internal.gyp:ppapi_ipc',
'../skia/skia.gyp:skia',
'<(webkit_src_dir)/Source/WebKit/chromium/WebKit.gyp:webkit',
'../third_party/smhasher/smhasher.gyp:pmurhash',
Expand Down
2 changes: 1 addition & 1 deletion content/content_ppapi_plugin.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
'dependencies': [
'../base/base.gyp:base',
'../ppapi/ppapi_internal.gyp:ppapi_proxy',
'../ppapi/ppapi_internal.gyp:ppapi_ipc',
'../ui/ui.gyp:ui',
],
'sources': [
Expand Down
1 change: 1 addition & 0 deletions content/content_tests.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@
'../net/net.gyp:net_test_support',
'../ppapi/ppapi_internal.gyp:ppapi_host',
'../ppapi/ppapi_internal.gyp:ppapi_proxy',
'../ppapi/ppapi_internal.gyp:ppapi_ipc',
'../ppapi/ppapi_internal.gyp:ppapi_shared',
'../ppapi/ppapi_internal.gyp:ppapi_unittest_shared',
'../skia/skia.gyp:skia',
Expand Down
Loading

0 comments on commit 246fc49

Please sign in to comment.