Initial import of libmojo r405848
This brings libmojo in sync with libchrome.
Bug: 27569341
Test: mma -j32 libmojo
Change-Id: Ia7cb877e46dd3f86f18888b5d8d80bef5468b266
diff --git a/ipc/attachment_broker.h b/ipc/attachment_broker.h
new file mode 100644
index 0000000..a106e29
--- /dev/null
+++ b/ipc/attachment_broker.h
@@ -0,0 +1,176 @@
+// Copyright 2015 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 IPC_ATTACHMENT_BROKER_H_
+#define IPC_ATTACHMENT_BROKER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/process/process_handle.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+#include "ipc/brokerable_attachment.h"
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_listener.h"
+
+// If the platform has no attachments that need brokering, then it shouldn't
+// compile any code that calls member functions of AttachmentBroker. This
+// prevents symbols only used by AttachmentBroker and its subclasses from
+// making it into the binary.
+#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#define USE_ATTACHMENT_BROKER 1
+#else
+#define USE_ATTACHMENT_BROKER 0
+#endif // defined(OS_WIN)
+
+namespace base {
+class SequencedTaskRunner;
+class SingleThreadTaskRunner;
+};
+
+namespace IPC {
+
+class AttachmentBroker;
+class Endpoint;
+
+// Classes that inherit from this abstract base class are capable of
+// communicating with a broker to send and receive attachments to Chrome IPC
+// messages.
+class IPC_EXPORT SupportsAttachmentBrokering {
+ public:
+ // Returns an AttachmentBroker used to broker attachments of IPC messages to
+ // other processes. There must be exactly one AttachmentBroker per process.
+ virtual AttachmentBroker* GetAttachmentBroker() = 0;
+};
+
+// Responsible for brokering attachments to Chrome IPC messages. On platforms
+// that support attachment brokering, every IPC channel should have a reference
+// to a AttachmentBroker.
+// This class is not thread safe. The implementation of this class assumes that
+// it is only ever used on the same thread as its consumers.
+class IPC_EXPORT AttachmentBroker : public Listener {
+ public:
+ // A standard observer interface that allows consumers of the AttachmentBroker
+ // to be notified when a new attachment has been received.
+ class Observer {
+ public:
+ virtual void ReceivedBrokerableAttachmentWithId(
+ const BrokerableAttachment::AttachmentId& id) = 0;
+ };
+
+ // Each process has at most one attachment broker. The process is responsible
+ // for ensuring that |broker| stays alive for as long as the process is
+ // sending/receiving ipc messages.
+ static void SetGlobal(AttachmentBroker* broker);
+ static AttachmentBroker* GetGlobal();
+
+ AttachmentBroker();
+ ~AttachmentBroker() override;
+
+ // Sends |attachment| to |destination_process|. The implementation uses an
+ // IPC::Channel to communicate with the broker process. This may be the same
+ // IPC::Channel that is requesting the brokering of an attachment.
+ // Returns true on success and false otherwise.
+ virtual bool SendAttachmentToProcess(
+ const scoped_refptr<BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) = 0;
+
+ // Returns whether the attachment was available. If the attachment was
+ // available, populates the output parameter |attachment|.
+ bool GetAttachmentWithId(BrokerableAttachment::AttachmentId id,
+ scoped_refptr<BrokerableAttachment>* attachment);
+
+ // Any given observer should only ever add itself once to the observer list.
+ // Notifications to |observer| will be posted to |runner|.
+ // The |observer| is expected to call RemoveObserver() before being destroyed.
+ void AddObserver(Observer* observer,
+ const scoped_refptr<base::SequencedTaskRunner>& runner);
+ void RemoveObserver(Observer* observer);
+
+ // These two methods should only be called by the broker process.
+ //
+ // Each unprivileged process should have one IPC channel on which it
+ // communicates attachment information with the broker process. In the broker
+ // process, these channels must be registered and deregistered with the
+ // Attachment Broker as they are created and destroyed.
+ //
+ // Invocations of Send() on |endpoint| will occur on thread bound to |runner|.
+ virtual void RegisterCommunicationChannel(
+ Endpoint* endpoint,
+ scoped_refptr<base::SingleThreadTaskRunner> runner);
+ virtual void DeregisterCommunicationChannel(Endpoint* endpoint);
+
+ // In each unprivileged process, exactly one channel should be used to
+ // communicate brokerable attachments with the broker process.
+ virtual void RegisterBrokerCommunicationChannel(Endpoint* endpoint);
+ virtual void DeregisterBrokerCommunicationChannel(Endpoint* endpoint);
+
+ // Informs the attachment broker that a channel endpoint has received its
+ // peer's PID.
+ virtual void ReceivedPeerPid(base::ProcessId peer_pid);
+
+ // True if and only if this broker is privileged.
+ virtual bool IsPrivilegedBroker();
+
+ protected:
+ using AttachmentVector = std::vector<scoped_refptr<BrokerableAttachment>>;
+
+ // Adds |attachment| to |attachments_|, and notifies the observers.
+ void HandleReceivedAttachment(
+ const scoped_refptr<BrokerableAttachment>& attachment);
+
+ // Informs the observers that a new BrokerableAttachment has been received.
+ void NotifyObservers(const BrokerableAttachment::AttachmentId& id);
+
+ // Informs the observer identified by |unique_id| that a new
+ // BrokerableAttachment has been received.
+ void NotifyObserver(int unique_id,
+ const BrokerableAttachment::AttachmentId& id);
+
+ // This method is exposed for testing only.
+ AttachmentVector* get_attachments() { return &attachments_; }
+
+ base::Lock* get_lock() { return &lock_; }
+
+ private:
+#if defined(OS_WIN)
+ FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerUnprivilegedWinTest,
+ ReceiveValidMessage);
+ FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerUnprivilegedWinTest,
+ ReceiveInvalidMessage);
+#endif // defined(OS_WIN)
+
+ // A vector of BrokerableAttachments that have been received, but not yet
+ // consumed.
+ // A std::vector is used instead of a std::map because this container is
+ // expected to have few elements, for which a std::vector is expected to have
+ // better performance.
+ AttachmentVector attachments_;
+
+ struct ObserverInfo {
+ ObserverInfo();
+ ObserverInfo(const ObserverInfo& other);
+ ~ObserverInfo();
+
+ Observer* observer;
+ int unique_id;
+
+ // Notifications must be dispatched onto |runner|.
+ scoped_refptr<base::SequencedTaskRunner> runner;
+ };
+ std::vector<ObserverInfo> observers_;
+
+ // This member holds the last id given to an ObserverInfo.
+ int last_unique_id_;
+
+ // The AttachmentBroker can be accessed from any thread, so modifications to
+ // internal state must be guarded by a lock.
+ base::Lock lock_;
+ DISALLOW_COPY_AND_ASSIGN(AttachmentBroker);
+};
+
+} // namespace IPC
+
+#endif // IPC_ATTACHMENT_BROKER_H_
diff --git a/ipc/brokerable_attachment.cc b/ipc/brokerable_attachment.cc
new file mode 100644
index 0000000..96ce5bb
--- /dev/null
+++ b/ipc/brokerable_attachment.cc
@@ -0,0 +1,72 @@
+// Copyright 2015 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 "ipc/brokerable_attachment.h"
+
+#include <stddef.h>
+
+#include "build/build_config.h"
+#include "ipc/attachment_broker.h"
+
+namespace IPC {
+
+// BrokerableAttachment::AttachmentId ------------------------------------------
+#if !USE_ATTACHMENT_BROKER
+// static
+BrokerableAttachment::AttachmentId
+BrokerableAttachment::AttachmentId::CreateIdWithRandomNonce() {
+ CHECK(false) << "Platforms that don't support attachment brokering shouldn't "
+ "be trying to generating a random nonce.";
+ return AttachmentId();
+}
+#endif
+
+BrokerableAttachment::AttachmentId::AttachmentId() {
+ for (size_t i = 0; i < BrokerableAttachment::kNonceSize; ++i)
+ nonce[i] = 0;
+}
+
+BrokerableAttachment::AttachmentId::AttachmentId(const char* start_address,
+ size_t size) {
+ DCHECK(size == BrokerableAttachment::kNonceSize);
+ for (size_t i = 0; i < BrokerableAttachment::kNonceSize; ++i)
+ nonce[i] = start_address[i];
+}
+
+void BrokerableAttachment::AttachmentId::SerializeToBuffer(char* start_address,
+ size_t size) {
+ DCHECK(size == BrokerableAttachment::kNonceSize);
+ for (size_t i = 0; i < BrokerableAttachment::kNonceSize; ++i)
+ start_address[i] = nonce[i];
+}
+
+// BrokerableAttachment::BrokerableAttachment ----------------------------------
+
+BrokerableAttachment::BrokerableAttachment()
+ : id_(AttachmentId::CreateIdWithRandomNonce()) {}
+
+BrokerableAttachment::BrokerableAttachment(const AttachmentId& id) : id_(id) {}
+
+BrokerableAttachment::~BrokerableAttachment() {}
+
+BrokerableAttachment::AttachmentId BrokerableAttachment::GetIdentifier() const {
+ return id_;
+}
+
+bool BrokerableAttachment::NeedsBrokering() const {
+ return GetBrokerableType() == PLACEHOLDER;
+}
+
+BrokerableAttachment::Type BrokerableAttachment::GetType() const {
+ return TYPE_BROKERABLE_ATTACHMENT;
+}
+
+#if defined(OS_POSIX)
+base::PlatformFile BrokerableAttachment::TakePlatformFile() {
+ NOTREACHED();
+ return base::PlatformFile();
+}
+#endif // OS_POSIX
+
+} // namespace IPC
diff --git a/ipc/brokerable_attachment.h b/ipc/brokerable_attachment.h
new file mode 100644
index 0000000..50e7fd2
--- /dev/null
+++ b/ipc/brokerable_attachment.h
@@ -0,0 +1,91 @@
+// Copyright 2015 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 IPC_BROKERABLE_ATTACHMENT_H_
+#define IPC_BROKERABLE_ATTACHMENT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_message_attachment.h"
+
+namespace IPC {
+
+// This subclass of MessageAttachment requires an AttachmentBroker to be
+// attached to a Chrome IPC message.
+class IPC_EXPORT BrokerableAttachment : public MessageAttachment {
+ public:
+ static const size_t kNonceSize = 16;
+ // An id uniquely identifies an attachment sent via a broker.
+ struct IPC_EXPORT AttachmentId {
+ uint8_t nonce[kNonceSize];
+
+ // Generates an AttachmentId with an unguessable, random nonce.
+ static AttachmentId CreateIdWithRandomNonce();
+
+ // Creates an AttachmentId with a zeroed nonce. This should only be used by
+ // the IPC translation system, which requires that classes have a default
+ // constructor.
+ AttachmentId();
+
+ // Constructs an AttachmentId from a buffer.
+ AttachmentId(const char* start_address, size_t size);
+
+ // Writes the nonce into a buffer.
+ void SerializeToBuffer(char* start_address, size_t size);
+
+ bool operator==(const AttachmentId& rhs) const {
+ return std::equal(nonce, nonce + kNonceSize, rhs.nonce);
+ }
+
+ bool operator<(const AttachmentId& rhs) const {
+ return std::lexicographical_compare(nonce, nonce + kNonceSize, rhs.nonce,
+ rhs.nonce + kNonceSize);
+ }
+ };
+
+ enum BrokerableType {
+ PLACEHOLDER,
+ WIN_HANDLE,
+ MACH_PORT,
+ };
+
+ // The identifier is unique across all Chrome processes.
+ AttachmentId GetIdentifier() const;
+
+ // Whether the attachment still needs information from the broker before it
+ // can be used.
+ bool NeedsBrokering() const;
+
+ // Returns TYPE_BROKERABLE_ATTACHMENT
+ Type GetType() const override;
+
+ virtual BrokerableType GetBrokerableType() const = 0;
+
+// MessageAttachment override.
+#if defined(OS_POSIX)
+ base::PlatformFile TakePlatformFile() override;
+#endif // OS_POSIX
+
+ protected:
+ BrokerableAttachment();
+ BrokerableAttachment(const AttachmentId& id);
+ ~BrokerableAttachment() override;
+
+ private:
+ // This member uniquely identifies a BrokerableAttachment across all Chrome
+ // processes.
+ const AttachmentId id_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrokerableAttachment);
+};
+
+} // namespace IPC
+
+#endif // IPC_BROKERABLE_ATTACHMENT_H_
diff --git a/ipc/ipc_channel_handle.h b/ipc/ipc_channel_handle.h
new file mode 100644
index 0000000..2e9dc3e
--- /dev/null
+++ b/ipc/ipc_channel_handle.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2012 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 IPC_IPC_CHANNEL_HANDLE_H_
+#define IPC_IPC_CHANNEL_HANDLE_H_
+
+#include <string>
+
+#include "build/build_config.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#elif defined(OS_WIN)
+#include <windows.h>
+#endif // defined (OS_WIN)
+
+// On Windows, any process can create an IPC channel and others can fetch
+// it by name. We pass around the channel names over IPC.
+// On Windows the initialization of ChannelHandle with an existing pipe
+// handle is provided for convenience.
+// NOTE: A ChannelHandle with a pipe handle Will NOT be marshalled over IPC.
+
+// On POSIX, we instead pass around handles to channel endpoints via IPC.
+// When it's time to IPC a new channel endpoint around, we send both the
+// channel name as well as a base::FileDescriptor, which is itself a special
+// type that knows how to copy a socket endpoint over IPC.
+//
+// In sum, this data structure can be used to pass channel information by name
+// in both Windows and Posix. When passing a handle to a channel over IPC,
+// use this data structure only for POSIX.
+
+namespace IPC {
+
+struct ChannelHandle {
+ // Note that serialization for this object is defined in the ParamTraits
+ // template specialization in ipc_message_utils.h.
+ ChannelHandle() {}
+ // The name that is passed in should be an absolute path for Posix.
+ // Otherwise there may be a problem in IPC communication between
+ // processes with different working directories.
+ ChannelHandle(const std::string& n) : name(n) {}
+ ChannelHandle(const char* n) : name(n) {}
+#if defined(OS_WIN)
+ explicit ChannelHandle(HANDLE h) : pipe(h) {}
+#elif defined(OS_POSIX)
+ ChannelHandle(const std::string& n, const base::FileDescriptor& s)
+ : name(n), socket(s) {}
+#endif // defined(OS_POSIX)
+ ChannelHandle(mojo::MessagePipeHandle h) : mojo_handle(h) {}
+
+ std::string name;
+#if defined(OS_POSIX)
+ base::FileDescriptor socket;
+#elif defined(OS_WIN)
+ // A simple container to automatically initialize pipe handle
+ struct PipeHandle {
+ PipeHandle() : handle(NULL) {}
+ PipeHandle(HANDLE h) : handle(h) {}
+ HANDLE handle;
+ };
+ PipeHandle pipe;
+#endif // defined (OS_WIN)
+ mojo::MessagePipeHandle mojo_handle;
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_CHANNEL_HANDLE_H_
diff --git a/ipc/ipc_export.h b/ipc/ipc_export.h
new file mode 100644
index 0000000..e1cbe88
--- /dev/null
+++ b/ipc/ipc_export.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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 IPC_IPC_EXPORT_H_
+#define IPC_IPC_EXPORT_H_
+
+// Defines IPC_EXPORT so that functionality implemented by the IPC module can be
+// exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(IPC_IMPLEMENTATION)
+#define IPC_EXPORT __declspec(dllexport)
+#else
+#define IPC_EXPORT __declspec(dllimport)
+#endif // defined(IPC_IMPLEMENTATION)
+
+#else // defined(WIN32)
+
+#if defined(IPC_IMPLEMENTATION)
+#define IPC_EXPORT __attribute__((visibility("default")))
+#else
+#define IPC_EXPORT
+#endif
+
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define IPC_EXPORT
+#endif
+
+#endif // IPC_IPC_EXPORT_H_
diff --git a/ipc/ipc_listener.h b/ipc/ipc_listener.h
new file mode 100644
index 0000000..0277086
--- /dev/null
+++ b/ipc/ipc_listener.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2012 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 IPC_IPC_LISTENER_H_
+#define IPC_IPC_LISTENER_H_
+
+#include <stdint.h>
+
+#include "build/build_config.h"
+#include "ipc/ipc_export.h"
+
+namespace IPC {
+
+class Message;
+
+// Implemented by consumers of a Channel to receive messages.
+class IPC_EXPORT Listener {
+ public:
+ // Called when a message is received. Returns true iff the message was
+ // handled.
+ virtual bool OnMessageReceived(const Message& message) = 0;
+
+ // Called when the channel is connected and we have received the internal
+ // Hello message from the peer.
+ virtual void OnChannelConnected(int32_t peer_pid) {}
+
+ // Called when an error is detected that causes the channel to close.
+ // This method is not called when a channel is closed normally.
+ virtual void OnChannelError() {}
+
+ // Called when a message's deserialization failed.
+ virtual void OnBadMessageReceived(const Message& message) {}
+
+#if defined(OS_POSIX)
+ // Called on the server side when a channel that listens for connections
+ // denies an attempt to connect.
+ virtual void OnChannelDenied() {}
+
+ // Called on the server side when a channel that listens for connections
+ // has an error that causes the listening channel to close.
+ virtual void OnChannelListenError() {}
+#endif // OS_POSIX
+
+ protected:
+ virtual ~Listener() {}
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_LISTENER_H_
diff --git a/ipc/ipc_message.cc b/ipc/ipc_message.cc
new file mode 100644
index 0000000..83ee495
--- /dev/null
+++ b/ipc/ipc_message.cc
@@ -0,0 +1,305 @@
+// Copyright (c) 2012 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 "ipc/ipc_message.h"
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/atomic_sequence_num.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "ipc/attachment_broker.h"
+#include "ipc/ipc_message_attachment.h"
+#include "ipc/ipc_message_attachment_set.h"
+#include "ipc/placeholder_brokerable_attachment.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#include "ipc/ipc_platform_file_attachment_posix.h"
+#endif
+
+namespace {
+
+base::StaticAtomicSequenceNumber g_ref_num;
+
+// Create a reference number for identifying IPC messages in traces. The return
+// values has the reference number stored in the upper 24 bits, leaving the low
+// 8 bits set to 0 for use as flags.
+inline uint32_t GetRefNumUpper24() {
+ base::trace_event::TraceLog* trace_log =
+ base::trace_event::TraceLog::GetInstance();
+ uint32_t pid = trace_log ? trace_log->process_id() : 0;
+ uint32_t count = g_ref_num.GetNext();
+ // The 24 bit hash is composed of 14 bits of the count and 10 bits of the
+ // Process ID. With the current trace event buffer cap, the 14-bit count did
+ // not appear to wrap during a trace. Note that it is not a big deal if
+ // collisions occur, as this is only used for debugging and trace analysis.
+ return ((pid << 14) | (count & 0x3fff)) << 8;
+}
+
+} // namespace
+
+namespace IPC {
+
+//------------------------------------------------------------------------------
+
+Message::~Message() {
+}
+
+Message::Message() : base::Pickle(sizeof(Header)) {
+ header()->routing = header()->type = 0;
+ header()->flags = GetRefNumUpper24();
+#if USE_ATTACHMENT_BROKER
+ header()->num_brokered_attachments = 0;
+#endif
+#if defined(OS_POSIX)
+ header()->num_fds = 0;
+ header()->pad = 0;
+#endif
+ Init();
+}
+
+Message::Message(int32_t routing_id, uint32_t type, PriorityValue priority)
+ : base::Pickle(sizeof(Header)) {
+ header()->routing = routing_id;
+ header()->type = type;
+ DCHECK((priority & 0xffffff00) == 0);
+ header()->flags = priority | GetRefNumUpper24();
+#if USE_ATTACHMENT_BROKER
+ header()->num_brokered_attachments = 0;
+#endif
+#if defined(OS_POSIX)
+ header()->num_fds = 0;
+ header()->pad = 0;
+#endif
+ Init();
+}
+
+Message::Message(const char* data, int data_len)
+ : base::Pickle(data, data_len) {
+ Init();
+}
+
+Message::Message(const Message& other) : base::Pickle(other) {
+ Init();
+ attachment_set_ = other.attachment_set_;
+ sender_pid_ = other.sender_pid_;
+}
+
+void Message::Init() {
+ dispatch_error_ = false;
+ sender_pid_ = base::kNullProcessId;
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ received_time_ = 0;
+ dont_log_ = false;
+ log_data_ = NULL;
+#endif
+}
+
+Message& Message::operator=(const Message& other) {
+ *static_cast<base::Pickle*>(this) = other;
+ attachment_set_ = other.attachment_set_;
+ sender_pid_ = other.sender_pid_;
+ return *this;
+}
+
+void Message::SetHeaderValues(int32_t routing, uint32_t type, uint32_t flags) {
+ // This should only be called when the message is already empty.
+ DCHECK(payload_size() == 0);
+
+ header()->routing = routing;
+ header()->type = type;
+ header()->flags = flags;
+}
+
+void Message::EnsureMessageAttachmentSet() {
+ if (attachment_set_.get() == NULL)
+ attachment_set_ = new MessageAttachmentSet;
+}
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+void Message::set_sent_time(int64_t time) {
+ DCHECK((header()->flags & HAS_SENT_TIME_BIT) == 0);
+ header()->flags |= HAS_SENT_TIME_BIT;
+ WriteInt64(time);
+}
+
+int64_t Message::sent_time() const {
+ if ((header()->flags & HAS_SENT_TIME_BIT) == 0)
+ return 0;
+
+ const char* data = end_of_payload();
+ data -= sizeof(int64_t);
+ return *(reinterpret_cast<const int64_t*>(data));
+}
+
+void Message::set_received_time(int64_t time) const {
+ received_time_ = time;
+}
+#endif
+
+Message::NextMessageInfo::NextMessageInfo()
+ : message_size(0), message_found(false), pickle_end(nullptr),
+ message_end(nullptr) {}
+Message::NextMessageInfo::~NextMessageInfo() {}
+
+Message::SerializedAttachmentIds
+Message::SerializedIdsOfBrokerableAttachments() {
+ DCHECK(HasBrokerableAttachments());
+ std::vector<scoped_refptr<IPC::BrokerableAttachment>> attachments(
+ attachment_set_->GetBrokerableAttachments());
+ CHECK_LE(attachments.size(), std::numeric_limits<size_t>::max() /
+ BrokerableAttachment::kNonceSize);
+ size_t size = attachments.size() * BrokerableAttachment::kNonceSize;
+ char* buffer = static_cast<char*>(malloc(size));
+ for (size_t i = 0; i < attachments.size(); ++i) {
+ char* start_range = buffer + i * BrokerableAttachment::kNonceSize;
+ BrokerableAttachment::AttachmentId id = attachments[i]->GetIdentifier();
+ id.SerializeToBuffer(start_range, BrokerableAttachment::kNonceSize);
+ }
+ SerializedAttachmentIds ids;
+ ids.buffer = buffer;
+ ids.size = size;
+ return ids;
+}
+
+// static
+void Message::FindNext(const char* range_start,
+ const char* range_end,
+ NextMessageInfo* info) {
+ DCHECK(info);
+ info->message_found = false;
+ info->message_size = 0;
+
+ size_t pickle_size = 0;
+ if (!base::Pickle::PeekNext(sizeof(Header),
+ range_start, range_end, &pickle_size))
+ return;
+
+ bool have_entire_pickle =
+ static_cast<size_t>(range_end - range_start) >= pickle_size;
+
+#if USE_ATTACHMENT_BROKER
+ // TODO(dskiba): determine message_size when entire pickle is not available
+
+ if (!have_entire_pickle)
+ return;
+
+ const char* pickle_end = range_start + pickle_size;
+
+ // The data is not copied.
+ Message message(range_start, static_cast<int>(pickle_size));
+ size_t num_attachments = message.header()->num_brokered_attachments;
+
+ // Check for possible overflows.
+ size_t max_size_t = std::numeric_limits<size_t>::max();
+ if (num_attachments >= max_size_t / BrokerableAttachment::kNonceSize)
+ return;
+
+ size_t attachment_length = num_attachments * BrokerableAttachment::kNonceSize;
+ if (pickle_size > max_size_t - attachment_length)
+ return;
+
+ // Check whether the range includes the attachments.
+ size_t buffer_length = static_cast<size_t>(range_end - range_start);
+ if (buffer_length < attachment_length + pickle_size)
+ return;
+
+ for (size_t i = 0; i < num_attachments; ++i) {
+ const char* attachment_start =
+ pickle_end + i * BrokerableAttachment::kNonceSize;
+ BrokerableAttachment::AttachmentId id(attachment_start,
+ BrokerableAttachment::kNonceSize);
+ info->attachment_ids.push_back(id);
+ }
+ info->message_end =
+ pickle_end + num_attachments * BrokerableAttachment::kNonceSize;
+ info->message_size = info->message_end - range_start;
+#else
+ info->message_size = pickle_size;
+
+ if (!have_entire_pickle)
+ return;
+
+ const char* pickle_end = range_start + pickle_size;
+
+ info->message_end = pickle_end;
+#endif // USE_ATTACHMENT_BROKER
+
+ info->pickle_end = pickle_end;
+ info->message_found = true;
+}
+
+bool Message::AddPlaceholderBrokerableAttachmentWithId(
+ BrokerableAttachment::AttachmentId id) {
+ scoped_refptr<PlaceholderBrokerableAttachment> attachment(
+ new PlaceholderBrokerableAttachment(id));
+ return attachment_set()->AddAttachment(attachment);
+}
+
+bool Message::WriteAttachment(
+ scoped_refptr<base::Pickle::Attachment> attachment) {
+ bool brokerable;
+ size_t index;
+ bool success = attachment_set()->AddAttachment(
+ make_scoped_refptr(static_cast<MessageAttachment*>(attachment.get())),
+ &index, &brokerable);
+ DCHECK(success);
+
+ // NOTE: If you add more data to the pickle, make sure to update
+ // PickleSizer::AddAttachment.
+
+ // Write the type of descriptor.
+ WriteBool(brokerable);
+
+ // Write the index of the descriptor so that we don't have to
+ // keep the current descriptor as extra decoding state when deserialising.
+ WriteInt(static_cast<int>(index));
+
+#if USE_ATTACHMENT_BROKER
+ if (brokerable)
+ header()->num_brokered_attachments++;
+#endif
+
+ return success;
+}
+
+bool Message::ReadAttachment(
+ base::PickleIterator* iter,
+ scoped_refptr<base::Pickle::Attachment>* attachment) const {
+ bool brokerable;
+ if (!iter->ReadBool(&brokerable))
+ return false;
+
+ int index;
+ if (!iter->ReadInt(&index))
+ return false;
+
+ MessageAttachmentSet* attachment_set = attachment_set_.get();
+ if (!attachment_set)
+ return false;
+
+ *attachment = brokerable
+ ? attachment_set->GetBrokerableAttachmentAt(index)
+ : attachment_set->GetNonBrokerableAttachmentAt(index);
+
+ return nullptr != attachment->get();
+}
+
+bool Message::HasAttachments() const {
+ return attachment_set_.get() && !attachment_set_->empty();
+}
+
+bool Message::HasMojoHandles() const {
+ return attachment_set_.get() && attachment_set_->num_mojo_handles() > 0;
+}
+
+bool Message::HasBrokerableAttachments() const {
+ return attachment_set_.get() &&
+ attachment_set_->num_brokerable_attachments() > 0;
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_message.h b/ipc/ipc_message.h
new file mode 100644
index 0000000..56c3a46
--- /dev/null
+++ b/ipc/ipc_message.h
@@ -0,0 +1,346 @@
+// Copyright (c) 2012 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 IPC_IPC_MESSAGE_H_
+#define IPC_IPC_MESSAGE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/pickle.h"
+#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
+#include "ipc/attachment_broker.h"
+#include "ipc/brokerable_attachment.h"
+#include "ipc/ipc_export.h"
+
+#if !defined(NDEBUG)
+#define IPC_MESSAGE_LOG_ENABLED
+#endif
+
+namespace IPC {
+
+namespace internal {
+class ChannelReader;
+} // namespace internal
+
+//------------------------------------------------------------------------------
+
+struct LogData;
+class MessageAttachment;
+class MessageAttachmentSet;
+
+class IPC_EXPORT Message : public base::Pickle {
+ public:
+ enum PriorityValue {
+ PRIORITY_LOW = 1,
+ PRIORITY_NORMAL,
+ PRIORITY_HIGH
+ };
+
+ // Bit values used in the flags field.
+ // Upper 24 bits of flags store a reference number, so this enum is limited to
+ // 8 bits.
+ enum {
+ PRIORITY_MASK = 0x03, // Low 2 bits of store the priority value.
+ SYNC_BIT = 0x04,
+ REPLY_BIT = 0x08,
+ REPLY_ERROR_BIT = 0x10,
+ UNBLOCK_BIT = 0x20,
+ PUMPING_MSGS_BIT = 0x40,
+ HAS_SENT_TIME_BIT = 0x80,
+ };
+
+ ~Message() override;
+
+ Message();
+
+ // Initialize a message with a user-defined type, priority value, and
+ // destination WebView ID.
+ Message(int32_t routing_id, uint32_t type, PriorityValue priority);
+
+ // Initializes a message from a const block of data. The data is not copied;
+ // instead the data is merely referenced by this message. Only const methods
+ // should be used on the message when initialized this way.
+ Message(const char* data, int data_len);
+
+ Message(const Message& other);
+ Message& operator=(const Message& other);
+
+ PriorityValue priority() const {
+ return static_cast<PriorityValue>(header()->flags & PRIORITY_MASK);
+ }
+
+ // True if this is a synchronous message.
+ void set_sync() {
+ header()->flags |= SYNC_BIT;
+ }
+ bool is_sync() const {
+ return (header()->flags & SYNC_BIT) != 0;
+ }
+
+ // Set this on a reply to a synchronous message.
+ void set_reply() {
+ header()->flags |= REPLY_BIT;
+ }
+
+ bool is_reply() const {
+ return (header()->flags & REPLY_BIT) != 0;
+ }
+
+ // Set this on a reply to a synchronous message to indicate that no receiver
+ // was found.
+ void set_reply_error() {
+ header()->flags |= REPLY_ERROR_BIT;
+ }
+
+ bool is_reply_error() const {
+ return (header()->flags & REPLY_ERROR_BIT) != 0;
+ }
+
+ // Normally when a receiver gets a message and they're blocked on a
+ // synchronous message Send, they buffer a message. Setting this flag causes
+ // the receiver to be unblocked and the message to be dispatched immediately.
+ void set_unblock(bool unblock) {
+ if (unblock) {
+ header()->flags |= UNBLOCK_BIT;
+ } else {
+ header()->flags &= ~UNBLOCK_BIT;
+ }
+ }
+
+ bool should_unblock() const {
+ return (header()->flags & UNBLOCK_BIT) != 0;
+ }
+
+ // Tells the receiver that the caller is pumping messages while waiting
+ // for the result.
+ bool is_caller_pumping_messages() const {
+ return (header()->flags & PUMPING_MSGS_BIT) != 0;
+ }
+
+ void set_dispatch_error() const {
+ dispatch_error_ = true;
+ }
+
+ bool dispatch_error() const {
+ return dispatch_error_;
+ }
+
+ uint32_t type() const {
+ return header()->type;
+ }
+
+ int32_t routing_id() const {
+ return header()->routing;
+ }
+
+ void set_routing_id(int32_t new_id) {
+ header()->routing = new_id;
+ }
+
+ uint32_t flags() const {
+ return header()->flags;
+ }
+
+ // Sets all the given header values. The message should be empty at this
+ // call.
+ void SetHeaderValues(int32_t routing, uint32_t type, uint32_t flags);
+
+ template<class T, class S, class P>
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter,
+ void (T::*func)()) {
+ (obj->*func)();
+ return true;
+ }
+
+ template<class T, class S, class P>
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter,
+ void (T::*func)(P*)) {
+ (obj->*func)(parameter);
+ return true;
+ }
+
+ // Used for async messages with no parameters.
+ static void Log(std::string* name, const Message* msg, std::string* l) {
+ }
+
+ // The static method FindNext() returns several pieces of information, which
+ // are aggregated into an instance of this struct.
+ struct IPC_EXPORT NextMessageInfo {
+ NextMessageInfo();
+ ~NextMessageInfo();
+
+ // Total message size. Always valid if |message_found| is true.
+ // If |message_found| is false but we could determine message size
+ // from the header, this field is non-zero. Otherwise it's zero.
+ size_t message_size;
+ // Whether an entire message was found in the given memory range.
+ bool message_found;
+ // Only filled in if |message_found| is true.
+ // The start address is passed into FindNext() by the caller, so isn't
+ // repeated in this struct. The end address of the pickle should be used to
+ // construct a base::Pickle.
+ const char* pickle_end;
+ // Only filled in if |message_found| is true.
+ // The end address of the message should be used to determine the start
+ // address of the next message.
+ const char* message_end;
+ // If the message has brokerable attachments, this vector will contain the
+ // ids of the brokerable attachments. The caller of FindNext() is
+ // responsible for adding the attachments to the message.
+ std::vector<BrokerableAttachment::AttachmentId> attachment_ids;
+ };
+
+ struct SerializedAttachmentIds {
+ void* buffer;
+ size_t size;
+ };
+ // Creates a buffer that contains a serialization of the ids of the brokerable
+ // attachments of the message. This buffer is intended to be sent over the IPC
+ // channel immediately after the pickled message. The caller takes ownership
+ // of the buffer.
+ // This method should only be called if the message has brokerable
+ // attachments.
+ SerializedAttachmentIds SerializedIdsOfBrokerableAttachments();
+
+ // |info| is an output parameter and must not be nullptr.
+ static void FindNext(const char* range_start,
+ const char* range_end,
+ NextMessageInfo* info);
+
+ // Adds a placeholder brokerable attachment that must be replaced before the
+ // message can be dispatched.
+ bool AddPlaceholderBrokerableAttachmentWithId(
+ BrokerableAttachment::AttachmentId id);
+
+ // WriteAttachment appends |attachment| to the end of the set. It returns
+ // false iff the set is full.
+ bool WriteAttachment(
+ scoped_refptr<base::Pickle::Attachment> attachment) override;
+ // ReadAttachment parses an attachment given the parsing state |iter| and
+ // writes it to |*attachment|. It returns true on success.
+ bool ReadAttachment(
+ base::PickleIterator* iter,
+ scoped_refptr<base::Pickle::Attachment>* attachment) const override;
+ // Returns true if there are any attachment in this message.
+ bool HasAttachments() const override;
+ // Returns true if there are any MojoHandleAttachments in this message.
+ bool HasMojoHandles() const;
+ // Whether the message has any brokerable attachments.
+ bool HasBrokerableAttachments() const;
+
+ void set_sender_pid(base::ProcessId id) { sender_pid_ = id; }
+ base::ProcessId get_sender_pid() const { return sender_pid_; }
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ // Adds the outgoing time from Time::Now() at the end of the message and sets
+ // a bit to indicate that it's been added.
+ void set_sent_time(int64_t time);
+ int64_t sent_time() const;
+
+ void set_received_time(int64_t time) const;
+ int64_t received_time() const { return received_time_; }
+ void set_output_params(const std::string& op) const { output_params_ = op; }
+ const std::string& output_params() const { return output_params_; }
+ // The following four functions are needed so we can log sync messages with
+ // delayed replies. We stick the log data from the sent message into the
+ // reply message, so that when it's sent and we have the output parameters
+ // we can log it. As such, we set a flag on the sent message to not log it.
+ void set_sync_log_data(LogData* data) const { log_data_ = data; }
+ LogData* sync_log_data() const { return log_data_; }
+ void set_dont_log() const { dont_log_ = true; }
+ bool dont_log() const { return dont_log_; }
+#endif
+
+ protected:
+ friend class Channel;
+ friend class ChannelMojo;
+ friend class ChannelNacl;
+ friend class ChannelPosix;
+ friend class ChannelWin;
+ friend class internal::ChannelReader;
+ friend class MessageReplyDeserializer;
+ friend class SyncMessage;
+
+#pragma pack(push, 4)
+ struct Header : base::Pickle::Header {
+ int32_t routing; // ID of the view that this message is destined for
+ uint32_t type; // specifies the user-defined message type
+ uint32_t flags; // specifies control flags for the message
+#if USE_ATTACHMENT_BROKER
+ // The number of brokered attachments included with this message. The
+ // ids of the brokered attachment ids are sent immediately after the pickled
+ // message, before the next pickled message is sent.
+ uint32_t num_brokered_attachments;
+#endif
+#if defined(OS_POSIX)
+ uint16_t num_fds; // the number of descriptors included with this message
+ uint16_t pad; // explicitly initialize this to appease valgrind
+#endif
+ };
+#pragma pack(pop)
+
+ Header* header() {
+ return headerT<Header>();
+ }
+ const Header* header() const {
+ return headerT<Header>();
+ }
+
+ void Init();
+
+ // Used internally to support IPC::Listener::OnBadMessageReceived.
+ mutable bool dispatch_error_;
+
+ // The set of file descriptors associated with this message.
+ scoped_refptr<MessageAttachmentSet> attachment_set_;
+
+ // Ensure that a MessageAttachmentSet is allocated
+ void EnsureMessageAttachmentSet();
+
+ MessageAttachmentSet* attachment_set() {
+ EnsureMessageAttachmentSet();
+ return attachment_set_.get();
+ }
+ const MessageAttachmentSet* attachment_set() const {
+ return attachment_set_.get();
+ }
+
+ // The process id of the sender of the message. This member is populated with
+ // a valid value for every message dispatched to listeners.
+ base::ProcessId sender_pid_;
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ // Used for logging.
+ mutable int64_t received_time_;
+ mutable std::string output_params_;
+ mutable LogData* log_data_;
+ mutable bool dont_log_;
+#endif
+
+ FRIEND_TEST_ALL_PREFIXES(IPCMessageTest, FindNext);
+ FRIEND_TEST_ALL_PREFIXES(IPCMessageTest, FindNextOverflow);
+};
+
+//------------------------------------------------------------------------------
+
+} // namespace IPC
+
+enum SpecialRoutingIDs {
+ // indicates that we don't have a routing ID yet.
+ MSG_ROUTING_NONE = -2,
+
+ // indicates a general message not sent to a particular tab.
+ MSG_ROUTING_CONTROL = INT32_MAX,
+};
+
+#define IPC_REPLY_ID 0xFFFFFFF0 // Special message id for replies
+#define IPC_LOGGING_ID 0xFFFFFFF1 // Special message id for logging
+
+#endif // IPC_IPC_MESSAGE_H_
diff --git a/ipc/ipc_message_attachment.cc b/ipc/ipc_message_attachment.cc
new file mode 100644
index 0000000..83440ae
--- /dev/null
+++ b/ipc/ipc_message_attachment.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2015 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 "ipc/ipc_message_attachment.h"
+
+namespace IPC {
+
+MessageAttachment::MessageAttachment() {
+}
+
+MessageAttachment::~MessageAttachment() {
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_message_attachment.h b/ipc/ipc_message_attachment.h
new file mode 100644
index 0000000..7f7137d
--- /dev/null
+++ b/ipc/ipc_message_attachment.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2015 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 IPC_IPC_MESSAGE_ATTACHMENT_H_
+#define IPC_IPC_MESSAGE_ATTACHMENT_H_
+
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/pickle.h"
+#include "build/build_config.h"
+#include "ipc/ipc_export.h"
+
+namespace IPC {
+
+// Auxiliary data sent with |Message|. This can be a platform file descriptor
+// or a mojo |MessagePipe|. |GetType()| returns the type of the subclass.
+class IPC_EXPORT MessageAttachment : public base::Pickle::Attachment {
+ public:
+ enum Type {
+ TYPE_PLATFORM_FILE, // The instance is |PlatformFileAttachment|.
+ TYPE_MOJO_HANDLE, // The instance is |MojoHandleAttachment|.
+ TYPE_BROKERABLE_ATTACHMENT, // The instance is |BrokerableAttachment|.
+ };
+
+ virtual Type GetType() const = 0;
+
+#if defined(OS_POSIX)
+ virtual base::PlatformFile TakePlatformFile() = 0;
+#endif // OS_POSIX
+
+ protected:
+ friend class base::RefCountedThreadSafe<MessageAttachment>;
+ MessageAttachment();
+ ~MessageAttachment() override;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageAttachment);
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_MESSAGE_ATTACHMENT_H_
diff --git a/ipc/ipc_message_attachment_set.cc b/ipc/ipc_message_attachment_set.cc
new file mode 100644
index 0000000..3b7eefb
--- /dev/null
+++ b/ipc/ipc_message_attachment_set.cc
@@ -0,0 +1,250 @@
+// Copyright (c) 2011 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 "ipc/ipc_message_attachment_set.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+#include "ipc/brokerable_attachment.h"
+#include "ipc/ipc_message_attachment.h"
+
+#if defined(OS_POSIX)
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "ipc/ipc_platform_file_attachment_posix.h"
+#endif // OS_POSIX
+
+namespace IPC {
+
+namespace {
+
+unsigned count_attachments_of_type(
+ const std::vector<scoped_refptr<MessageAttachment>>& attachments,
+ MessageAttachment::Type type) {
+ unsigned count = 0;
+ for (const scoped_refptr<MessageAttachment>& attachment : attachments) {
+ if (attachment->GetType() == type)
+ ++count;
+ }
+ return count;
+}
+
+} // namespace
+
+MessageAttachmentSet::MessageAttachmentSet()
+ : consumed_descriptor_highwater_(0) {
+}
+
+MessageAttachmentSet::~MessageAttachmentSet() {
+ if (consumed_descriptor_highwater_ == num_non_brokerable_attachments())
+ return;
+
+ // We close all the owning descriptors. If this message should have
+ // been transmitted, then closing those with close flags set mirrors
+ // the expected behaviour.
+ //
+ // If this message was received with more descriptors than expected
+ // (which could a DOS against the browser by a rogue renderer) then all
+ // the descriptors have their close flag set and we free all the extra
+ // kernel resources.
+ LOG(WARNING) << "MessageAttachmentSet destroyed with unconsumed descriptors: "
+ << consumed_descriptor_highwater_ << "/" << num_descriptors();
+}
+
+unsigned MessageAttachmentSet::num_descriptors() const {
+ return count_attachments_of_type(attachments_,
+ MessageAttachment::TYPE_PLATFORM_FILE);
+}
+
+unsigned MessageAttachmentSet::num_mojo_handles() const {
+ return count_attachments_of_type(attachments_,
+ MessageAttachment::TYPE_MOJO_HANDLE);
+}
+
+unsigned MessageAttachmentSet::num_brokerable_attachments() const {
+ return static_cast<unsigned>(brokerable_attachments_.size());
+}
+
+unsigned MessageAttachmentSet::num_non_brokerable_attachments() const {
+ return static_cast<unsigned>(attachments_.size());
+}
+
+unsigned MessageAttachmentSet::size() const {
+ return static_cast<unsigned>(attachments_.size() +
+ brokerable_attachments_.size());
+}
+
+bool MessageAttachmentSet::AddAttachment(
+ scoped_refptr<MessageAttachment> attachment,
+ size_t* index,
+ bool* brokerable) {
+#if defined(OS_POSIX)
+ if (attachment->GetType() == MessageAttachment::TYPE_PLATFORM_FILE &&
+ num_descriptors() == kMaxDescriptorsPerMessage) {
+ DLOG(WARNING) << "Cannot add file descriptor. MessageAttachmentSet full.";
+ return false;
+ }
+#endif
+
+ switch (attachment->GetType()) {
+ case MessageAttachment::TYPE_PLATFORM_FILE:
+ case MessageAttachment::TYPE_MOJO_HANDLE:
+ attachments_.push_back(attachment);
+ *index = attachments_.size() - 1;
+ *brokerable = false;
+ return true;
+ case MessageAttachment::TYPE_BROKERABLE_ATTACHMENT:
+ BrokerableAttachment* brokerable_attachment =
+ static_cast<BrokerableAttachment*>(attachment.get());
+ scoped_refptr<BrokerableAttachment> a(brokerable_attachment);
+ brokerable_attachments_.push_back(a);
+ *index = brokerable_attachments_.size() - 1;
+ *brokerable = true;
+ return true;
+ }
+ return false;
+}
+
+bool MessageAttachmentSet::AddAttachment(
+ scoped_refptr<MessageAttachment> attachment) {
+ bool brokerable;
+ size_t index;
+ return AddAttachment(attachment, &index, &brokerable);
+}
+
+scoped_refptr<MessageAttachment>
+MessageAttachmentSet::GetNonBrokerableAttachmentAt(unsigned index) {
+ if (index >= num_non_brokerable_attachments()) {
+ DLOG(WARNING) << "Accessing out of bound index:" << index << "/"
+ << num_non_brokerable_attachments();
+ return scoped_refptr<MessageAttachment>();
+ }
+
+ // We should always walk the descriptors in order, so it's reasonable to
+ // enforce this. Consider the case where a compromised renderer sends us
+ // the following message:
+ //
+ // ExampleMsg:
+ // num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m}
+ //
+ // Here the renderer sent us a message which should have a descriptor, but
+ // actually sent two in an attempt to fill our fd table and kill us. By
+ // setting the index of the descriptor in the message to 1 (it should be
+ // 0), we would record a highwater of 1 and then consider all the
+ // descriptors to have been used.
+ //
+ // So we can either track of the use of each descriptor in a bitset, or we
+ // can enforce that we walk the indexes strictly in order.
+ //
+ // There's one more wrinkle: When logging messages, we may reparse them. So
+ // we have an exception: When the consumed_descriptor_highwater_ is at the
+ // end of the array and index 0 is requested, we reset the highwater value.
+ // TODO(morrita): This is absurd. This "wringle" disallow to introduce clearer
+ // ownership model. Only client is NaclIPCAdapter. See crbug.com/415294
+ if (index == 0 &&
+ consumed_descriptor_highwater_ == num_non_brokerable_attachments()) {
+ consumed_descriptor_highwater_ = 0;
+ }
+
+ if (index != consumed_descriptor_highwater_)
+ return scoped_refptr<MessageAttachment>();
+
+ consumed_descriptor_highwater_ = index + 1;
+
+ return attachments_[index];
+}
+
+scoped_refptr<MessageAttachment>
+MessageAttachmentSet::GetBrokerableAttachmentAt(unsigned index) {
+ if (index >= num_brokerable_attachments()) {
+ DLOG(WARNING) << "Accessing out of bound index:" << index << "/"
+ << num_brokerable_attachments();
+ return scoped_refptr<MessageAttachment>();
+ }
+
+ scoped_refptr<BrokerableAttachment> brokerable_attachment(
+ brokerable_attachments_[index]);
+ return scoped_refptr<MessageAttachment>(brokerable_attachment.get());
+}
+
+void MessageAttachmentSet::CommitAllDescriptors() {
+ attachments_.clear();
+ consumed_descriptor_highwater_ = 0;
+}
+
+std::vector<scoped_refptr<IPC::BrokerableAttachment>>
+MessageAttachmentSet::GetBrokerableAttachments() const {
+ return brokerable_attachments_;
+}
+
+void MessageAttachmentSet::ReplacePlaceholderWithAttachment(
+ const scoped_refptr<BrokerableAttachment>& attachment) {
+ DCHECK_NE(BrokerableAttachment::PLACEHOLDER, attachment->GetBrokerableType());
+ for (auto it = brokerable_attachments_.begin();
+ it != brokerable_attachments_.end(); ++it) {
+ if ((*it)->GetBrokerableType() == BrokerableAttachment::PLACEHOLDER &&
+ (*it)->GetIdentifier() == attachment->GetIdentifier()) {
+ *it = attachment;
+ return;
+ }
+ }
+
+ // This function should only be called if there is a placeholder ready to be
+ // replaced.
+ NOTREACHED();
+}
+
+#if defined(OS_POSIX)
+
+void MessageAttachmentSet::PeekDescriptors(base::PlatformFile* buffer) const {
+ for (size_t i = 0; i != attachments_.size(); ++i)
+ buffer[i] = internal::GetPlatformFile(attachments_[i]);
+}
+
+bool MessageAttachmentSet::ContainsDirectoryDescriptor() const {
+ struct stat st;
+
+ for (auto i = attachments_.begin(); i != attachments_.end(); ++i) {
+ if (fstat(internal::GetPlatformFile(*i), &st) == 0 && S_ISDIR(st.st_mode))
+ return true;
+ }
+
+ return false;
+}
+
+void MessageAttachmentSet::ReleaseFDsToClose(
+ std::vector<base::PlatformFile>* fds) {
+ for (size_t i = 0; i < attachments_.size(); ++i) {
+ internal::PlatformFileAttachment* file =
+ static_cast<internal::PlatformFileAttachment*>(attachments_[i].get());
+ if (file->Owns())
+ fds->push_back(file->TakePlatformFile());
+ }
+
+ CommitAllDescriptors();
+}
+
+void MessageAttachmentSet::AddDescriptorsToOwn(const base::PlatformFile* buffer,
+ unsigned count) {
+ DCHECK(count <= kMaxDescriptorsPerMessage);
+ DCHECK_EQ(num_descriptors(), 0u);
+ DCHECK_EQ(consumed_descriptor_highwater_, 0u);
+
+ attachments_.reserve(count);
+ for (unsigned i = 0; i < count; ++i)
+ AddAttachment(
+ new internal::PlatformFileAttachment(base::ScopedFD(buffer[i])));
+}
+
+#endif // OS_POSIX
+
+} // namespace IPC
+
+
diff --git a/ipc/ipc_message_attachment_set.h b/ipc/ipc_message_attachment_set.h
new file mode 100644
index 0000000..764c818
--- /dev/null
+++ b/ipc/ipc_message_attachment_set.h
@@ -0,0 +1,163 @@
+// Copyright (c) 2011 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 IPC_IPC_MESSAGE_ATTACHMENT_SET_H_
+#define IPC_IPC_MESSAGE_ATTACHMENT_SET_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "build/build_config.h"
+#include "ipc/ipc_export.h"
+
+#if defined(OS_POSIX)
+#include "base/files/file.h"
+#endif
+
+namespace IPC {
+
+class BrokerableAttachment;
+class MessageAttachment;
+
+// -----------------------------------------------------------------------------
+// A MessageAttachmentSet is an ordered set of MessageAttachment objects
+// associated with an IPC message. There are three types of MessageAttachments:
+// 1) TYPE_PLATFORM_FILE is transmitted over the Channel's underlying
+// UNIX domain socket
+// 2) TYPE_MOJO_HANDLE is transmitted over the Mojo MessagePipe.
+// 3) TYPE_BROKERABLE_ATTACHMENT is transmitted by the Attachment Broker.
+// Any given IPC Message can have attachments of type (1) or (2), but not both.
+// These are stored in |attachments_|. Attachments of type (3) are stored in
+// |brokerable_attachments_|.
+//
+// To produce a deterministic ordering, all attachments in |attachments_| are
+// considered to come before those in |brokerable_attachments_|. These
+// attachments are transmitted across different communication channels, and
+// multiplexed by the receiver, so ordering between them cannot be guaranteed.
+//
+// -----------------------------------------------------------------------------
+class IPC_EXPORT MessageAttachmentSet
+ : public base::RefCountedThreadSafe<MessageAttachmentSet> {
+ public:
+ MessageAttachmentSet();
+
+ // Return the number of attachments
+ unsigned size() const;
+ // Return the number of file descriptors
+ unsigned num_descriptors() const;
+ // Return the number of mojo handles in the attachment set
+ unsigned num_mojo_handles() const;
+ // Return the number of brokerable attachments in the attachment set.
+ unsigned num_brokerable_attachments() const;
+ // Return the number of non-brokerable attachments in the attachment set.
+ unsigned num_non_brokerable_attachments() const;
+
+ // Return true if no unconsumed descriptors remain
+ bool empty() const { return 0 == size(); }
+
+ // Returns whether the attachment was successfully added.
+ // |index| is an output variable. On success, it contains the index of the
+ // newly added attachment.
+ // |brokerable| is an output variable. On success, it describes which vector
+ // the attachment was added to.
+ bool AddAttachment(scoped_refptr<MessageAttachment> attachment,
+ size_t* index,
+ bool* brokerable);
+
+ // Similar to the above method, but without output variables.
+ bool AddAttachment(scoped_refptr<MessageAttachment> attachment);
+
+ // Take the nth non-brokerable attachment from the beginning of the vector,
+ // Code using this /must/ access the attachments in order, and must do it at
+ // most once.
+ //
+ // This interface is designed for the deserialising code as it doesn't
+ // support close flags.
+ // returns: an attachment, or nullptr on error
+ scoped_refptr<MessageAttachment> GetNonBrokerableAttachmentAt(unsigned index);
+
+ // Similar to GetNonBrokerableAttachmentAt, but there are no ordering
+ // requirements.
+ scoped_refptr<MessageAttachment> GetBrokerableAttachmentAt(unsigned index);
+
+ // This must be called after transmitting the descriptors returned by
+ // PeekDescriptors. It marks all the non-brokerable descriptors as consumed
+ // and closes those which are auto-close.
+ void CommitAllDescriptors();
+
+ // Returns a vector of all brokerable attachments.
+ std::vector<scoped_refptr<IPC::BrokerableAttachment>>
+ GetBrokerableAttachments() const;
+
+ // Replaces a placeholder brokerable attachment with |attachment|, matching
+ // them by their id.
+ void ReplacePlaceholderWithAttachment(
+ const scoped_refptr<BrokerableAttachment>& attachment);
+
+#if defined(OS_POSIX)
+ // This is the maximum number of descriptors per message. We need to know this
+ // because the control message kernel interface has to be given a buffer which
+ // is large enough to store all the descriptor numbers. Otherwise the kernel
+ // tells us that it truncated the control data and the extra descriptors are
+ // lost.
+ //
+ // In debugging mode, it's a fatal error to try and add more than this number
+ // of descriptors to a MessageAttachmentSet.
+ static const size_t kMaxDescriptorsPerMessage = 7;
+
+ // ---------------------------------------------------------------------------
+ // Interfaces for transmission...
+
+ // Fill an array with file descriptors without 'consuming' them.
+ // CommitAllDescriptors must be called after these descriptors have been
+ // transmitted.
+ // buffer: (output) a buffer of, at least, size() integers.
+ void PeekDescriptors(base::PlatformFile* buffer) const;
+ // Returns true if any contained file descriptors appear to be handles to a
+ // directory.
+ bool ContainsDirectoryDescriptor() const;
+ // Fetch all filedescriptors with the "auto close" property. Used instead of
+ // CommitAllDescriptors() when closing must be handled manually.
+ void ReleaseFDsToClose(std::vector<base::PlatformFile>* fds);
+
+ // ---------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------
+ // Interfaces for receiving...
+
+ // Set the contents of the set from the given buffer. This set must be empty
+ // before calling. The auto-close flag is set on all the descriptors so that
+ // unconsumed descriptors are closed on destruction.
+ void AddDescriptorsToOwn(const base::PlatformFile* buffer, unsigned count);
+
+#endif // OS_POSIX
+
+ // ---------------------------------------------------------------------------
+
+ private:
+ friend class base::RefCountedThreadSafe<MessageAttachmentSet>;
+
+ ~MessageAttachmentSet();
+
+ // All elements either have type TYPE_PLATFORM_FILE or TYPE_MOJO_HANDLE.
+ std::vector<scoped_refptr<MessageAttachment>> attachments_;
+
+ // All elements have type TYPE_BROKERABLE_ATTACHMENT.
+ std::vector<scoped_refptr<BrokerableAttachment>> brokerable_attachments_;
+
+ // This contains the index of the next descriptor which should be consumed.
+ // It's used in a couple of ways. Firstly, at destruction we can check that
+ // all the descriptors have been read (with GetNthDescriptor). Secondly, we
+ // can check that they are read in order.
+ mutable unsigned consumed_descriptor_highwater_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageAttachmentSet);
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_MESSAGE_ATTACHMENT_SET_H_
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
new file mode 100644
index 0000000..c1e1b9f
--- /dev/null
+++ b/ipc/ipc_message_start.h
@@ -0,0 +1,133 @@
+// Copyright 2012 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 IPC_IPC_MESSAGE_START_H_
+#define IPC_IPC_MESSAGE_START_H_
+
+// Used by IPC_BEGIN_MESSAGES so that each message class starts from a unique
+// base. Messages have unique IDs across channels in order for the IPC logging
+// code to figure out the message class from its ID.
+enum IPCMessageStart {
+ AutomationMsgStart = 0,
+ FrameMsgStart,
+ PageMsgStart,
+ ViewMsgStart,
+ InputMsgStart,
+ ProfileImportMsgStart,
+ TestMsgStart,
+ DevToolsMsgStart,
+ WorkerMsgStart,
+ NaClMsgStart,
+ UtilityMsgStart,
+ GpuChannelMsgStart,
+ GpuMsgStart,
+ MediaMsgStart,
+ ServiceMsgStart,
+ PpapiMsgStart,
+ FirefoxImporterUnittestMsgStart,
+ FileUtilitiesMsgStart,
+ DatabaseMsgStart,
+ DOMStorageMsgStart,
+ IndexedDBMsgStart,
+ SpeechRecognitionMsgStart,
+ AutofillMsgStart,
+ SafeBrowsingMsgStart,
+ P2PMsgStart,
+ ResourceMsgStart,
+ FileSystemMsgStart,
+ ChildProcessMsgStart,
+ ClipboardMsgStart,
+ BlobMsgStart,
+ AppCacheMsgStart,
+ AudioMsgStart,
+ MidiMsgStart,
+ ChromeMsgStart,
+ DragMsgStart,
+ PrintMsgStart,
+ SpellCheckMsgStart,
+ ExtensionMsgStart,
+ VideoCaptureMsgStart,
+ QuotaMsgStart,
+ TextInputClientMsgStart,
+ ChromeUtilityMsgStart,
+ MediaStreamMsgStart,
+ ChromeBenchmarkingMsgStart,
+ JavaBridgeMsgStart,
+ GamepadMsgStart,
+ ShellMsgStart,
+ AccessibilityMsgStart,
+ PrefetchMsgStart,
+ PrerenderMsgStart,
+ ChromotingMsgStart,
+ BrowserPluginMsgStart,
+ AndroidWebViewMsgStart,
+ MetroViewerMsgStart,
+ CCMsgStart,
+ MediaPlayerMsgStart,
+ TracingMsgStart,
+ PeerConnectionTrackerMsgStart,
+ VisitedLinkMsgStart,
+ AppShimMsgStart,
+ WebRtcLoggingMsgStart,
+ TtsMsgStart,
+ WebSocketMsgStart,
+ NaClHostMsgStart,
+ WebRTCIdentityMsgStart,
+ PowerMonitorMsgStart,
+ EncryptedMediaMsgStart,
+ CacheStorageMsgStart,
+ ServiceWorkerMsgStart,
+ MessagePortMsgStart,
+ EmbeddedWorkerMsgStart,
+ EmbeddedWorkerContextMsgStart,
+ CastMsgStart,
+ CdmMsgStart,
+ ScreenOrientationMsgStart,
+ MediaStreamTrackMetricsHostMsgStart,
+ ChromeExtensionMsgStart,
+ TranslateMsgStart,
+ PushMessagingMsgStart,
+ GinJavaBridgeMsgStart,
+ ChromeUtilityPrintingMsgStart,
+ AecDumpMsgStart,
+ OzoneGpuMsgStart,
+ ChromeUtilityExtensionsMsgStart,
+ PlatformNotificationMsgStart,
+ PDFMsgStart,
+ ManifestManagerMsgStart,
+ ExtensionUtilityMsgStart,
+ LayoutTestMsgStart,
+ NetworkHintsMsgStart,
+ BluetoothMsgStart,
+ CastMediaMsgStart,
+ AwMessagePortMsgStart,
+ SyncCompositorMsgStart,
+ ExtensionsGuestViewMsgStart,
+ GuestViewMsgStart,
+ // Note: CastCryptoMsgStart and CastChannelMsgStart reserved for Chromecast
+ // internal code. Contact gunsch@ before changing/removing.
+ CastCryptoMsgStart,
+ CastChannelMsgStart,
+ DataReductionProxyStart,
+ ContentSettingsMsgStart,
+ ChromeAppBannerMsgStart,
+ AttachmentBrokerMsgStart,
+ RenderProcessMsgStart,
+ PageLoadMetricsMsgStart,
+ MemoryMsgStart,
+ MediaSessionMsgStart,
+ IPCTestMsgStart,
+ ArcInstanceMsgStart,
+ ArcInstanceHostMsgStart,
+ DistillerMsgStart,
+ ArcCameraMsgStart,
+ DWriteFontProxyMsgStart,
+ MediaPlayerDelegateMsgStart,
+ SurfaceViewManagerMsgStart,
+ ExtensionWorkerMsgStart,
+ SubresourceFilterMsgStart,
+ LastIPCMsgStart // Must come last.
+};
+
+#endif // IPC_IPC_MESSAGE_START_H_
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc
new file mode 100644
index 0000000..60c12ab
--- /dev/null
+++ b/ipc/ipc_message_utils.cc
@@ -0,0 +1,1220 @@
+// Copyright (c) 2012 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 "ipc/ipc_message_utils.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/files/file_path.h"
+#include "base/json/json_writer.h"
+#include "base/strings/nullable_string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_message_attachment.h"
+#include "ipc/ipc_message_attachment_set.h"
+#include "ipc/ipc_mojo_param_traits.h"
+
+#if defined(OS_POSIX)
+#include "ipc/ipc_platform_file_attachment_posix.h"
+#endif
+
+#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
+#include "base/memory/shared_memory_handle.h"
+#endif // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "ipc/mach_port_mac.h"
+#endif
+
+#if defined(OS_WIN)
+#include <tchar.h>
+#include "ipc/handle_win.h"
+#endif
+
+namespace IPC {
+
+namespace {
+
+const int kMaxRecursionDepth = 100;
+
+template<typename CharType>
+void LogBytes(const std::vector<CharType>& data, std::string* out) {
+#if defined(OS_WIN)
+ // Windows has a GUI for logging, which can handle arbitrary binary data.
+ for (size_t i = 0; i < data.size(); ++i)
+ out->push_back(data[i]);
+#else
+ // On POSIX, we log to stdout, which we assume can display ASCII.
+ static const size_t kMaxBytesToLog = 100;
+ for (size_t i = 0; i < std::min(data.size(), kMaxBytesToLog); ++i) {
+ if (isprint(data[i]))
+ out->push_back(data[i]);
+ else
+ out->append(
+ base::StringPrintf("[%02X]", static_cast<unsigned char>(data[i])));
+ }
+ if (data.size() > kMaxBytesToLog) {
+ out->append(base::StringPrintf(
+ " and %u more bytes",
+ static_cast<unsigned>(data.size() - kMaxBytesToLog)));
+ }
+#endif
+}
+
+bool ReadValue(const base::Pickle* m,
+ base::PickleIterator* iter,
+ base::Value** value,
+ int recursion);
+
+void GetValueSize(base::PickleSizer* sizer,
+ const base::Value* value,
+ int recursion) {
+ if (recursion > kMaxRecursionDepth) {
+ LOG(WARNING) << "Max recursion depth hit in GetValueSize.";
+ return;
+ }
+
+ sizer->AddInt();
+ switch (value->GetType()) {
+ case base::Value::TYPE_NULL:
+ break;
+ case base::Value::TYPE_BOOLEAN:
+ sizer->AddBool();
+ break;
+ case base::Value::TYPE_INTEGER:
+ sizer->AddInt();
+ break;
+ case base::Value::TYPE_DOUBLE:
+ sizer->AddDouble();
+ break;
+ case base::Value::TYPE_STRING: {
+ const base::StringValue* result;
+ value->GetAsString(&result);
+ if (value->GetAsString(&result)) {
+ DCHECK(result);
+ GetParamSize(sizer, result->GetString());
+ } else {
+ std::string str;
+ bool as_string_result = value->GetAsString(&str);
+ DCHECK(as_string_result);
+ GetParamSize(sizer, str);
+ }
+ break;
+ }
+ case base::Value::TYPE_BINARY: {
+ const base::BinaryValue* binary =
+ static_cast<const base::BinaryValue*>(value);
+ sizer->AddData(static_cast<int>(binary->GetSize()));
+ break;
+ }
+ case base::Value::TYPE_DICTIONARY: {
+ sizer->AddInt();
+ const base::DictionaryValue* dict =
+ static_cast<const base::DictionaryValue*>(value);
+ for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
+ it.Advance()) {
+ GetParamSize(sizer, it.key());
+ GetValueSize(sizer, &it.value(), recursion + 1);
+ }
+ break;
+ }
+ case base::Value::TYPE_LIST: {
+ sizer->AddInt();
+ const base::ListValue* list = static_cast<const base::ListValue*>(value);
+ for (const auto& entry : *list) {
+ GetValueSize(sizer, entry.get(), recursion + 1);
+ }
+ break;
+ }
+ default:
+ NOTREACHED() << "Invalid base::Value type.";
+ }
+}
+
+void WriteValue(base::Pickle* m, const base::Value* value, int recursion) {
+ bool result;
+ if (recursion > kMaxRecursionDepth) {
+ LOG(WARNING) << "Max recursion depth hit in WriteValue.";
+ return;
+ }
+
+ m->WriteInt(value->GetType());
+
+ switch (value->GetType()) {
+ case base::Value::TYPE_NULL:
+ break;
+ case base::Value::TYPE_BOOLEAN: {
+ bool val;
+ result = value->GetAsBoolean(&val);
+ DCHECK(result);
+ WriteParam(m, val);
+ break;
+ }
+ case base::Value::TYPE_INTEGER: {
+ int val;
+ result = value->GetAsInteger(&val);
+ DCHECK(result);
+ WriteParam(m, val);
+ break;
+ }
+ case base::Value::TYPE_DOUBLE: {
+ double val;
+ result = value->GetAsDouble(&val);
+ DCHECK(result);
+ WriteParam(m, val);
+ break;
+ }
+ case base::Value::TYPE_STRING: {
+ std::string val;
+ result = value->GetAsString(&val);
+ DCHECK(result);
+ WriteParam(m, val);
+ break;
+ }
+ case base::Value::TYPE_BINARY: {
+ const base::BinaryValue* binary =
+ static_cast<const base::BinaryValue*>(value);
+ m->WriteData(binary->GetBuffer(), static_cast<int>(binary->GetSize()));
+ break;
+ }
+ case base::Value::TYPE_DICTIONARY: {
+ const base::DictionaryValue* dict =
+ static_cast<const base::DictionaryValue*>(value);
+
+ WriteParam(m, static_cast<int>(dict->size()));
+
+ for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
+ it.Advance()) {
+ WriteParam(m, it.key());
+ WriteValue(m, &it.value(), recursion + 1);
+ }
+ break;
+ }
+ case base::Value::TYPE_LIST: {
+ const base::ListValue* list = static_cast<const base::ListValue*>(value);
+ WriteParam(m, static_cast<int>(list->GetSize()));
+ for (const auto& entry : *list) {
+ WriteValue(m, entry.get(), recursion + 1);
+ }
+ break;
+ }
+ }
+}
+
+// Helper for ReadValue that reads a DictionaryValue into a pre-allocated
+// object.
+bool ReadDictionaryValue(const base::Pickle* m,
+ base::PickleIterator* iter,
+ base::DictionaryValue* value,
+ int recursion) {
+ int size;
+ if (!ReadParam(m, iter, &size))
+ return false;
+
+ for (int i = 0; i < size; ++i) {
+ std::string key;
+ base::Value* subval;
+ if (!ReadParam(m, iter, &key) ||
+ !ReadValue(m, iter, &subval, recursion + 1))
+ return false;
+ value->SetWithoutPathExpansion(key, subval);
+ }
+
+ return true;
+}
+
+// Helper for ReadValue that reads a ReadListValue into a pre-allocated
+// object.
+bool ReadListValue(const base::Pickle* m,
+ base::PickleIterator* iter,
+ base::ListValue* value,
+ int recursion) {
+ int size;
+ if (!ReadParam(m, iter, &size))
+ return false;
+
+ for (int i = 0; i < size; ++i) {
+ base::Value* subval;
+ if (!ReadValue(m, iter, &subval, recursion + 1))
+ return false;
+ value->Set(i, subval);
+ }
+
+ return true;
+}
+
+bool ReadValue(const base::Pickle* m,
+ base::PickleIterator* iter,
+ base::Value** value,
+ int recursion) {
+ if (recursion > kMaxRecursionDepth) {
+ LOG(WARNING) << "Max recursion depth hit in ReadValue.";
+ return false;
+ }
+
+ int type;
+ if (!ReadParam(m, iter, &type))
+ return false;
+
+ switch (type) {
+ case base::Value::TYPE_NULL:
+ *value = base::Value::CreateNullValue().release();
+ break;
+ case base::Value::TYPE_BOOLEAN: {
+ bool val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = new base::FundamentalValue(val);
+ break;
+ }
+ case base::Value::TYPE_INTEGER: {
+ int val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = new base::FundamentalValue(val);
+ break;
+ }
+ case base::Value::TYPE_DOUBLE: {
+ double val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = new base::FundamentalValue(val);
+ break;
+ }
+ case base::Value::TYPE_STRING: {
+ std::string val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = new base::StringValue(val);
+ break;
+ }
+ case base::Value::TYPE_BINARY: {
+ const char* data;
+ int length;
+ if (!iter->ReadData(&data, &length))
+ return false;
+ std::unique_ptr<base::BinaryValue> val =
+ base::BinaryValue::CreateWithCopiedBuffer(data, length);
+ *value = val.release();
+ break;
+ }
+ case base::Value::TYPE_DICTIONARY: {
+ std::unique_ptr<base::DictionaryValue> val(new base::DictionaryValue());
+ if (!ReadDictionaryValue(m, iter, val.get(), recursion))
+ return false;
+ *value = val.release();
+ break;
+ }
+ case base::Value::TYPE_LIST: {
+ std::unique_ptr<base::ListValue> val(new base::ListValue());
+ if (!ReadListValue(m, iter, val.get(), recursion))
+ return false;
+ *value = val.release();
+ break;
+ }
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+// -----------------------------------------------------------------------------
+
+LogData::LogData()
+ : routing_id(0),
+ type(0),
+ sent(0),
+ receive(0),
+ dispatch(0) {
+}
+
+LogData::LogData(const LogData& other) = default;
+
+LogData::~LogData() {
+}
+
+void ParamTraits<bool>::Log(const param_type& p, std::string* l) {
+ l->append(p ? "true" : "false");
+}
+
+void ParamTraits<signed char>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddBytes(sizeof(param_type));
+}
+
+void ParamTraits<signed char>::Write(base::Pickle* m, const param_type& p) {
+ m->WriteBytes(&p, sizeof(param_type));
+}
+
+bool ParamTraits<signed char>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ const char* data;
+ if (!iter->ReadBytes(&data, sizeof(param_type)))
+ return false;
+ memcpy(r, data, sizeof(param_type));
+ return true;
+}
+
+void ParamTraits<signed char>::Log(const param_type& p, std::string* l) {
+ l->append(base::IntToString(p));
+}
+
+void ParamTraits<unsigned char>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddBytes(sizeof(param_type));
+}
+
+void ParamTraits<unsigned char>::Write(base::Pickle* m, const param_type& p) {
+ m->WriteBytes(&p, sizeof(param_type));
+}
+
+bool ParamTraits<unsigned char>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ const char* data;
+ if (!iter->ReadBytes(&data, sizeof(param_type)))
+ return false;
+ memcpy(r, data, sizeof(param_type));
+ return true;
+}
+
+void ParamTraits<unsigned char>::Log(const param_type& p, std::string* l) {
+ l->append(base::UintToString(p));
+}
+
+void ParamTraits<unsigned short>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddBytes(sizeof(param_type));
+}
+
+void ParamTraits<unsigned short>::Write(base::Pickle* m, const param_type& p) {
+ m->WriteBytes(&p, sizeof(param_type));
+}
+
+bool ParamTraits<unsigned short>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ const char* data;
+ if (!iter->ReadBytes(&data, sizeof(param_type)))
+ return false;
+ memcpy(r, data, sizeof(param_type));
+ return true;
+}
+
+void ParamTraits<unsigned short>::Log(const param_type& p, std::string* l) {
+ l->append(base::UintToString(p));
+}
+
+void ParamTraits<int>::Log(const param_type& p, std::string* l) {
+ l->append(base::IntToString(p));
+}
+
+void ParamTraits<unsigned int>::Log(const param_type& p, std::string* l) {
+ l->append(base::UintToString(p));
+}
+
+#if defined(OS_WIN) || defined(OS_LINUX) || \
+ (defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS))
+void ParamTraits<long>::Log(const param_type& p, std::string* l) {
+ l->append(base::Int64ToString(static_cast<int64_t>(p)));
+}
+
+void ParamTraits<unsigned long>::Log(const param_type& p, std::string* l) {
+ l->append(base::Uint64ToString(static_cast<uint64_t>(p)));
+}
+#endif
+
+void ParamTraits<long long>::Log(const param_type& p, std::string* l) {
+ l->append(base::Int64ToString(static_cast<int64_t>(p)));
+}
+
+void ParamTraits<unsigned long long>::Log(const param_type& p, std::string* l) {
+ l->append(base::Uint64ToString(p));
+}
+
+void ParamTraits<float>::Log(const param_type& p, std::string* l) {
+ l->append(base::StringPrintf("%e", p));
+}
+
+void ParamTraits<double>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddBytes(sizeof(param_type));
+}
+
+void ParamTraits<double>::Write(base::Pickle* m, const param_type& p) {
+ m->WriteBytes(reinterpret_cast<const char*>(&p), sizeof(param_type));
+}
+
+bool ParamTraits<double>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ const char *data;
+ if (!iter->ReadBytes(&data, sizeof(*r))) {
+ NOTREACHED();
+ return false;
+ }
+ memcpy(r, data, sizeof(param_type));
+ return true;
+}
+
+void ParamTraits<double>::Log(const param_type& p, std::string* l) {
+ l->append(base::StringPrintf("%e", p));
+}
+
+
+void ParamTraits<std::string>::Log(const param_type& p, std::string* l) {
+ l->append(p);
+}
+
+void ParamTraits<base::string16>::Log(const param_type& p, std::string* l) {
+ l->append(base::UTF16ToUTF8(p));
+}
+
+void ParamTraits<std::vector<char>>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddData(static_cast<int>(p.size()));
+}
+
+void ParamTraits<std::vector<char>>::Write(base::Pickle* m,
+ const param_type& p) {
+ if (p.empty()) {
+ m->WriteData(NULL, 0);
+ } else {
+ m->WriteData(&p.front(), static_cast<int>(p.size()));
+ }
+}
+
+bool ParamTraits<std::vector<char>>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ const char *data;
+ int data_size = 0;
+ if (!iter->ReadData(&data, &data_size) || data_size < 0)
+ return false;
+ r->resize(data_size);
+ if (data_size)
+ memcpy(&r->front(), data, data_size);
+ return true;
+}
+
+void ParamTraits<std::vector<char> >::Log(const param_type& p, std::string* l) {
+ LogBytes(p, l);
+}
+
+void ParamTraits<std::vector<unsigned char>>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddData(static_cast<int>(p.size()));
+}
+
+void ParamTraits<std::vector<unsigned char>>::Write(base::Pickle* m,
+ const param_type& p) {
+ if (p.empty()) {
+ m->WriteData(NULL, 0);
+ } else {
+ m->WriteData(reinterpret_cast<const char*>(&p.front()),
+ static_cast<int>(p.size()));
+ }
+}
+
+bool ParamTraits<std::vector<unsigned char>>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ const char *data;
+ int data_size = 0;
+ if (!iter->ReadData(&data, &data_size) || data_size < 0)
+ return false;
+ r->resize(data_size);
+ if (data_size)
+ memcpy(&r->front(), data, data_size);
+ return true;
+}
+
+void ParamTraits<std::vector<unsigned char> >::Log(const param_type& p,
+ std::string* l) {
+ LogBytes(p, l);
+}
+
+void ParamTraits<std::vector<bool>>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p.size()));
+ for (size_t i = 0; i < p.size(); ++i)
+ GetParamSize(sizer, static_cast<bool>(p[i]));
+}
+
+void ParamTraits<std::vector<bool>>::Write(base::Pickle* m,
+ const param_type& p) {
+ WriteParam(m, static_cast<int>(p.size()));
+ // Cast to bool below is required because libc++'s
+ // vector<bool>::const_reference is different from bool, and we want to avoid
+ // writing an extra specialization of ParamTraits for it.
+ for (size_t i = 0; i < p.size(); i++)
+ WriteParam(m, static_cast<bool>(p[i]));
+}
+
+bool ParamTraits<std::vector<bool>>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int size;
+ // ReadLength() checks for < 0 itself.
+ if (!iter->ReadLength(&size))
+ return false;
+ r->resize(size);
+ for (int i = 0; i < size; i++) {
+ bool value;
+ if (!ReadParam(m, iter, &value))
+ return false;
+ (*r)[i] = value;
+ }
+ return true;
+}
+
+void ParamTraits<std::vector<bool> >::Log(const param_type& p, std::string* l) {
+ for (size_t i = 0; i < p.size(); ++i) {
+ if (i != 0)
+ l->push_back(' ');
+ LogParam(static_cast<bool>(p[i]), l);
+ }
+}
+
+void ParamTraits<BrokerableAttachment::AttachmentId>::Write(
+ base::Pickle* m,
+ const param_type& p) {
+ m->WriteBytes(p.nonce, BrokerableAttachment::kNonceSize);
+}
+
+bool ParamTraits<BrokerableAttachment::AttachmentId>::Read(
+ const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ const char* data;
+ if (!iter->ReadBytes(&data, BrokerableAttachment::kNonceSize))
+ return false;
+ memcpy(r->nonce, data, BrokerableAttachment::kNonceSize);
+ return true;
+}
+
+void ParamTraits<BrokerableAttachment::AttachmentId>::Log(const param_type& p,
+ std::string* l) {
+ l->append(base::HexEncode(p.nonce, BrokerableAttachment::kNonceSize));
+}
+
+void ParamTraits<base::DictionaryValue>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetValueSize(sizer, &p, 0);
+}
+
+void ParamTraits<base::DictionaryValue>::Write(base::Pickle* m,
+ const param_type& p) {
+ WriteValue(m, &p, 0);
+}
+
+bool ParamTraits<base::DictionaryValue>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int type;
+ if (!ReadParam(m, iter, &type) || type != base::Value::TYPE_DICTIONARY)
+ return false;
+
+ return ReadDictionaryValue(m, iter, r, 0);
+}
+
+void ParamTraits<base::DictionaryValue>::Log(const param_type& p,
+ std::string* l) {
+ std::string json;
+ base::JSONWriter::Write(p, &json);
+ l->append(json);
+}
+
+#if defined(OS_POSIX)
+void ParamTraits<base::FileDescriptor>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, p.fd >= 0);
+ if (p.fd >= 0)
+ sizer->AddAttachment();
+}
+
+void ParamTraits<base::FileDescriptor>::Write(base::Pickle* m,
+ const param_type& p) {
+ const bool valid = p.fd >= 0;
+ WriteParam(m, valid);
+
+ if (!valid)
+ return;
+
+ if (p.auto_close) {
+ if (!m->WriteAttachment(
+ new internal::PlatformFileAttachment(base::ScopedFD(p.fd))))
+ NOTREACHED();
+ } else {
+ if (!m->WriteAttachment(new internal::PlatformFileAttachment(p.fd)))
+ NOTREACHED();
+ }
+}
+
+bool ParamTraits<base::FileDescriptor>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ *r = base::FileDescriptor();
+
+ bool valid;
+ if (!ReadParam(m, iter, &valid))
+ return false;
+
+ // TODO(morrita): Seems like this should return false.
+ if (!valid)
+ return true;
+
+ scoped_refptr<base::Pickle::Attachment> attachment;
+ if (!m->ReadAttachment(iter, &attachment))
+ return false;
+
+ *r = base::FileDescriptor(
+ static_cast<MessageAttachment*>(attachment.get())->TakePlatformFile(),
+ true);
+ return true;
+}
+
+void ParamTraits<base::FileDescriptor>::Log(const param_type& p,
+ std::string* l) {
+ if (p.auto_close) {
+ l->append(base::StringPrintf("FD(%d auto-close)", p.fd));
+ } else {
+ l->append(base::StringPrintf("FD(%d)", p.fd));
+ }
+}
+#endif // defined(OS_POSIX)
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+void ParamTraits<base::SharedMemoryHandle>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, p.GetMemoryObject());
+ uint32_t dummy = 0;
+ GetParamSize(sizer, dummy);
+}
+
+void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m,
+ const param_type& p) {
+ MachPortMac mach_port_mac(p.GetMemoryObject());
+ ParamTraits<MachPortMac>::Write(m, mach_port_mac);
+ size_t size = 0;
+ bool result = p.GetSize(&size);
+ DCHECK(result);
+ ParamTraits<uint32_t>::Write(m, static_cast<uint32_t>(size));
+
+ // If the caller intended to pass ownership to the IPC stack, release a
+ // reference.
+ if (p.OwnershipPassesToIPC())
+ p.Close();
+}
+
+bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ MachPortMac mach_port_mac;
+ if (!ParamTraits<MachPortMac>::Read(m, iter, &mach_port_mac))
+ return false;
+
+ uint32_t size;
+ if (!ParamTraits<uint32_t>::Read(m, iter, &size))
+ return false;
+
+ *r = base::SharedMemoryHandle(mach_port_mac.get_mach_port(),
+ static_cast<size_t>(size),
+ base::GetCurrentProcId());
+ return true;
+}
+
+void ParamTraits<base::SharedMemoryHandle>::Log(const param_type& p,
+ std::string* l) {
+ l->append("Mach port: ");
+ LogParam(p.GetMemoryObject(), l);
+}
+
+#elif defined(OS_WIN)
+void ParamTraits<base::SharedMemoryHandle>::GetSize(base::PickleSizer* s,
+ const param_type& p) {
+ GetParamSize(s, p.NeedsBrokering());
+ if (p.NeedsBrokering()) {
+ GetParamSize(s, p.GetHandle());
+ } else {
+ GetParamSize(s, HandleToLong(p.GetHandle()));
+ }
+}
+
+void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m,
+ const param_type& p) {
+ m->WriteBool(p.NeedsBrokering());
+
+ if (p.NeedsBrokering()) {
+ HandleWin handle_win(p.GetHandle(), HandleWin::DUPLICATE);
+ ParamTraits<HandleWin>::Write(m, handle_win);
+
+ // If the caller intended to pass ownership to the IPC stack, release a
+ // reference.
+ if (p.OwnershipPassesToIPC() && p.BelongsToCurrentProcess())
+ p.Close();
+ } else {
+ m->WriteInt(HandleToLong(p.GetHandle()));
+ }
+}
+
+bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ bool needs_brokering;
+ if (!iter->ReadBool(&needs_brokering))
+ return false;
+
+ if (needs_brokering) {
+ HandleWin handle_win;
+ if (!ParamTraits<HandleWin>::Read(m, iter, &handle_win))
+ return false;
+ *r = base::SharedMemoryHandle(handle_win.get_handle(),
+ base::GetCurrentProcId());
+ return true;
+ }
+
+ int handle_int;
+ if (!iter->ReadInt(&handle_int))
+ return false;
+ HANDLE handle = LongToHandle(handle_int);
+ *r = base::SharedMemoryHandle(handle, base::GetCurrentProcId());
+ return true;
+}
+
+void ParamTraits<base::SharedMemoryHandle>::Log(const param_type& p,
+ std::string* l) {
+ LogParam(p.GetHandle(), l);
+ l->append(" needs brokering: ");
+ LogParam(p.NeedsBrokering(), l);
+}
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
+void ParamTraits<base::FilePath>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ p.GetSizeForPickle(sizer);
+}
+
+void ParamTraits<base::FilePath>::Write(base::Pickle* m, const param_type& p) {
+ p.WriteToPickle(m);
+}
+
+bool ParamTraits<base::FilePath>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return r->ReadFromPickle(iter);
+}
+
+void ParamTraits<base::FilePath>::Log(const param_type& p, std::string* l) {
+ ParamTraits<base::FilePath::StringType>::Log(p.value(), l);
+}
+
+void ParamTraits<base::ListValue>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetValueSize(sizer, &p, 0);
+}
+
+void ParamTraits<base::ListValue>::Write(base::Pickle* m, const param_type& p) {
+ WriteValue(m, &p, 0);
+}
+
+bool ParamTraits<base::ListValue>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int type;
+ if (!ReadParam(m, iter, &type) || type != base::Value::TYPE_LIST)
+ return false;
+
+ return ReadListValue(m, iter, r, 0);
+}
+
+void ParamTraits<base::ListValue>::Log(const param_type& p, std::string* l) {
+ std::string json;
+ base::JSONWriter::Write(p, &json);
+ l->append(json);
+}
+
+void ParamTraits<base::NullableString16>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, p.string());
+ GetParamSize(sizer, p.is_null());
+}
+
+void ParamTraits<base::NullableString16>::Write(base::Pickle* m,
+ const param_type& p) {
+ WriteParam(m, p.string());
+ WriteParam(m, p.is_null());
+}
+
+bool ParamTraits<base::NullableString16>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ base::string16 string;
+ if (!ReadParam(m, iter, &string))
+ return false;
+ bool is_null;
+ if (!ReadParam(m, iter, &is_null))
+ return false;
+ *r = base::NullableString16(string, is_null);
+ return true;
+}
+
+void ParamTraits<base::NullableString16>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.string(), l);
+ l->append(", ");
+ LogParam(p.is_null(), l);
+ l->append(")");
+}
+
+void ParamTraits<base::File::Info>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, p.size);
+ GetParamSize(sizer, p.is_directory);
+ GetParamSize(sizer, p.last_modified.ToDoubleT());
+ GetParamSize(sizer, p.last_accessed.ToDoubleT());
+ GetParamSize(sizer, p.creation_time.ToDoubleT());
+}
+
+void ParamTraits<base::File::Info>::Write(base::Pickle* m,
+ const param_type& p) {
+ WriteParam(m, p.size);
+ WriteParam(m, p.is_directory);
+ WriteParam(m, p.last_modified.ToDoubleT());
+ WriteParam(m, p.last_accessed.ToDoubleT());
+ WriteParam(m, p.creation_time.ToDoubleT());
+}
+
+bool ParamTraits<base::File::Info>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* p) {
+ double last_modified, last_accessed, creation_time;
+ if (!ReadParam(m, iter, &p->size) ||
+ !ReadParam(m, iter, &p->is_directory) ||
+ !ReadParam(m, iter, &last_modified) ||
+ !ReadParam(m, iter, &last_accessed) ||
+ !ReadParam(m, iter, &creation_time))
+ return false;
+ p->last_modified = base::Time::FromDoubleT(last_modified);
+ p->last_accessed = base::Time::FromDoubleT(last_accessed);
+ p->creation_time = base::Time::FromDoubleT(creation_time);
+ return true;
+}
+
+void ParamTraits<base::File::Info>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.size, l);
+ l->append(",");
+ LogParam(p.is_directory, l);
+ l->append(",");
+ LogParam(p.last_modified.ToDoubleT(), l);
+ l->append(",");
+ LogParam(p.last_accessed.ToDoubleT(), l);
+ l->append(",");
+ LogParam(p.creation_time.ToDoubleT(), l);
+ l->append(")");
+}
+
+void ParamTraits<base::Time>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddInt64();
+}
+
+void ParamTraits<base::Time>::Write(base::Pickle* m, const param_type& p) {
+ ParamTraits<int64_t>::Write(m, p.ToInternalValue());
+}
+
+bool ParamTraits<base::Time>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int64_t value;
+ if (!ParamTraits<int64_t>::Read(m, iter, &value))
+ return false;
+ *r = base::Time::FromInternalValue(value);
+ return true;
+}
+
+void ParamTraits<base::Time>::Log(const param_type& p, std::string* l) {
+ ParamTraits<int64_t>::Log(p.ToInternalValue(), l);
+}
+
+void ParamTraits<base::TimeDelta>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddInt64();
+}
+
+void ParamTraits<base::TimeDelta>::Write(base::Pickle* m, const param_type& p) {
+ ParamTraits<int64_t>::Write(m, p.ToInternalValue());
+}
+
+bool ParamTraits<base::TimeDelta>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int64_t value;
+ bool ret = ParamTraits<int64_t>::Read(m, iter, &value);
+ if (ret)
+ *r = base::TimeDelta::FromInternalValue(value);
+
+ return ret;
+}
+
+void ParamTraits<base::TimeDelta>::Log(const param_type& p, std::string* l) {
+ ParamTraits<int64_t>::Log(p.ToInternalValue(), l);
+}
+
+void ParamTraits<base::TimeTicks>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddInt64();
+}
+
+void ParamTraits<base::TimeTicks>::Write(base::Pickle* m, const param_type& p) {
+ ParamTraits<int64_t>::Write(m, p.ToInternalValue());
+}
+
+bool ParamTraits<base::TimeTicks>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int64_t value;
+ bool ret = ParamTraits<int64_t>::Read(m, iter, &value);
+ if (ret)
+ *r = base::TimeTicks::FromInternalValue(value);
+
+ return ret;
+}
+
+void ParamTraits<base::TimeTicks>::Log(const param_type& p, std::string* l) {
+ ParamTraits<int64_t>::Log(p.ToInternalValue(), l);
+}
+
+void ParamTraits<IPC::ChannelHandle>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, p.name);
+#if defined(OS_POSIX)
+ GetParamSize(sizer, p.socket);
+#endif
+ GetParamSize(sizer, p.mojo_handle);
+}
+
+void ParamTraits<IPC::ChannelHandle>::Write(base::Pickle* m,
+ const param_type& p) {
+#if defined(OS_WIN)
+ // On Windows marshalling pipe handle is not supported.
+ DCHECK(p.pipe.handle == NULL);
+#endif // defined (OS_WIN)
+ WriteParam(m, p.name);
+#if defined(OS_POSIX)
+ WriteParam(m, p.socket);
+#endif
+ WriteParam(m, p.mojo_handle);
+}
+
+bool ParamTraits<IPC::ChannelHandle>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return ReadParam(m, iter, &r->name)
+#if defined(OS_POSIX)
+ && ReadParam(m, iter, &r->socket)
+#endif
+ && ReadParam(m, iter, &r->mojo_handle);
+}
+
+void ParamTraits<IPC::ChannelHandle>::Log(const param_type& p,
+ std::string* l) {
+ l->append(base::StringPrintf("ChannelHandle(%s", p.name.c_str()));
+#if defined(OS_POSIX)
+ l->append(", ");
+ ParamTraits<base::FileDescriptor>::Log(p.socket, l);
+#endif
+ l->append(", ");
+ LogParam(p.mojo_handle, l);
+ l->append(")");
+}
+
+void ParamTraits<LogData>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, p.channel);
+ GetParamSize(sizer, p.routing_id);
+ GetParamSize(sizer, p.type);
+ GetParamSize(sizer, p.flags);
+ GetParamSize(sizer, p.sent);
+ GetParamSize(sizer, p.receive);
+ GetParamSize(sizer, p.dispatch);
+ GetParamSize(sizer, p.message_name);
+ GetParamSize(sizer, p.params);
+}
+
+void ParamTraits<LogData>::Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, p.channel);
+ WriteParam(m, p.routing_id);
+ WriteParam(m, p.type);
+ WriteParam(m, p.flags);
+ WriteParam(m, p.sent);
+ WriteParam(m, p.receive);
+ WriteParam(m, p.dispatch);
+ WriteParam(m, p.message_name);
+ WriteParam(m, p.params);
+}
+
+bool ParamTraits<LogData>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return
+ ReadParam(m, iter, &r->channel) &&
+ ReadParam(m, iter, &r->routing_id) &&
+ ReadParam(m, iter, &r->type) &&
+ ReadParam(m, iter, &r->flags) &&
+ ReadParam(m, iter, &r->sent) &&
+ ReadParam(m, iter, &r->receive) &&
+ ReadParam(m, iter, &r->dispatch) &&
+ ReadParam(m, iter, &r->message_name) &&
+ ReadParam(m, iter, &r->params);
+}
+
+void ParamTraits<LogData>::Log(const param_type& p, std::string* l) {
+ // Doesn't make sense to implement this!
+}
+
+void ParamTraits<Message>::Write(base::Pickle* m, const Message& p) {
+#if defined(OS_POSIX)
+ // We don't serialize the file descriptors in the nested message, so there
+ // better not be any.
+ DCHECK(!p.HasAttachments());
+#endif
+
+ // Don't just write out the message. This is used to send messages between
+ // NaCl (Posix environment) and the browser (could be on Windows). The message
+ // header formats differ between these systems (so does handle sharing, but
+ // we already asserted we don't have any handles). So just write out the
+ // parts of the header we use.
+ //
+ // Be careful also to use only explicitly-sized types. The NaCl environment
+ // could be 64-bit and the host browser could be 32-bits. The nested message
+ // may or may not be safe to send between 32-bit and 64-bit systems, but we
+ // leave that up to the code sending the message to ensure.
+ m->WriteUInt32(static_cast<uint32_t>(p.routing_id()));
+ m->WriteUInt32(p.type());
+ m->WriteUInt32(p.flags());
+ m->WriteData(p.payload(), static_cast<uint32_t>(p.payload_size()));
+}
+
+bool ParamTraits<Message>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ Message* r) {
+ uint32_t routing_id, type, flags;
+ if (!iter->ReadUInt32(&routing_id) ||
+ !iter->ReadUInt32(&type) ||
+ !iter->ReadUInt32(&flags))
+ return false;
+
+ int payload_size;
+ const char* payload;
+ if (!iter->ReadData(&payload, &payload_size))
+ return false;
+
+ r->SetHeaderValues(static_cast<int32_t>(routing_id), type, flags);
+ return r->WriteBytes(payload, payload_size);
+}
+
+void ParamTraits<Message>::Log(const Message& p, std::string* l) {
+ l->append("<IPC::Message>");
+}
+
+#if defined(OS_WIN)
+void ParamTraits<HANDLE>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddInt();
+}
+
+// Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64
+// bit systems. That's why we use the Windows macros to convert to 32 bits.
+void ParamTraits<HANDLE>::Write(base::Pickle* m, const param_type& p) {
+ m->WriteInt(HandleToLong(p));
+}
+
+bool ParamTraits<HANDLE>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int32_t temp;
+ if (!iter->ReadInt(&temp))
+ return false;
+ *r = LongToHandle(temp);
+ return true;
+}
+
+void ParamTraits<HANDLE>::Log(const param_type& p, std::string* l) {
+ l->append(base::StringPrintf("0x%p", p));
+}
+
+void ParamTraits<LOGFONT>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddData(sizeof(LOGFONT));
+}
+
+void ParamTraits<LOGFONT>::Write(base::Pickle* m, const param_type& p) {
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(LOGFONT));
+}
+
+bool ParamTraits<LOGFONT>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ const char *data;
+ int data_size = 0;
+ if (iter->ReadData(&data, &data_size) && data_size == sizeof(LOGFONT)) {
+ const LOGFONT *font = reinterpret_cast<LOGFONT*>(const_cast<char*>(data));
+ if (_tcsnlen(font->lfFaceName, LF_FACESIZE) < LF_FACESIZE) {
+ memcpy(r, data, sizeof(LOGFONT));
+ return true;
+ }
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+void ParamTraits<LOGFONT>::Log(const param_type& p, std::string* l) {
+ l->append(base::StringPrintf("<LOGFONT>"));
+}
+
+void ParamTraits<MSG>::GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddData(sizeof(MSG));
+}
+
+void ParamTraits<MSG>::Write(base::Pickle* m, const param_type& p) {
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(MSG));
+}
+
+bool ParamTraits<MSG>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ const char *data;
+ int data_size = 0;
+ bool result = iter->ReadData(&data, &data_size);
+ if (result && data_size == sizeof(MSG)) {
+ memcpy(r, data, sizeof(MSG));
+ } else {
+ result = false;
+ NOTREACHED();
+ }
+
+ return result;
+}
+
+void ParamTraits<MSG>::Log(const param_type& p, std::string* l) {
+ l->append("<MSG>");
+}
+
+#endif // OS_WIN
+
+} // namespace IPC
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
new file mode 100644
index 0000000..6712d3c
--- /dev/null
+++ b/ipc/ipc_message_utils.h
@@ -0,0 +1,1149 @@
+// Copyright (c) 2012 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 IPC_IPC_MESSAGE_UTILS_H_
+#define IPC_IPC_MESSAGE_UTILS_H_
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "base/containers/small_map.h"
+#include "base/containers/stack_container.h"
+#include "base/files/file.h"
+#include "base/format_macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+#include "ipc/brokerable_attachment.h"
+#include "ipc/ipc_message_start.h"
+#include "ipc/ipc_param_traits.h"
+#include "ipc/ipc_sync_message.h"
+
+namespace base {
+class DictionaryValue;
+class FilePath;
+class ListValue;
+class NullableString16;
+class Time;
+class TimeDelta;
+class TimeTicks;
+struct FileDescriptor;
+
+#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
+class SharedMemoryHandle;
+#endif // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
+}
+
+namespace IPC {
+
+struct ChannelHandle;
+
+// -----------------------------------------------------------------------------
+// How we send IPC message logs across channels.
+struct IPC_EXPORT LogData {
+ LogData();
+ LogData(const LogData& other);
+ ~LogData();
+
+ std::string channel;
+ int32_t routing_id;
+ uint32_t type; // "User-defined" message type, from ipc_message.h.
+ std::string flags;
+ int64_t sent; // Time that the message was sent (i.e. at Send()).
+ int64_t receive; // Time before it was dispatched (i.e. before calling
+ // OnMessageReceived).
+ int64_t dispatch; // Time after it was dispatched (i.e. after calling
+ // OnMessageReceived).
+ std::string message_name;
+ std::string params;
+};
+
+//-----------------------------------------------------------------------------
+
+// A dummy struct to place first just to allow leading commas for all
+// members in the macro-generated constructor initializer lists.
+struct NoParams {
+};
+
+// Specializations are checked by 'IPC checker' part of find-bad-constructs
+// Clang plugin (see WriteParam() below for the details).
+template <typename... Ts>
+struct CheckedTuple {
+ typedef std::tuple<Ts...> Tuple;
+};
+
+template <class P>
+static inline void GetParamSize(base::PickleSizer* sizer, const P& p) {
+ typedef typename SimilarTypeTraits<P>::Type Type;
+ ParamTraits<Type>::GetSize(sizer, static_cast<const Type&>(p));
+}
+
+// This function is checked by 'IPC checker' part of find-bad-constructs
+// Clang plugin to make it's not called on the following types:
+// 1. long / unsigned long (but not typedefs to)
+// 2. intmax_t, uintmax_t, intptr_t, uintptr_t, wint_t,
+// size_t, rsize_t, ssize_t, ptrdiff_t, dev_t, off_t, clock_t,
+// time_t, suseconds_t (including typedefs to)
+// 3. Any template referencing types above (e.g. std::vector<size_t>)
+template <class P>
+static inline void WriteParam(base::Pickle* m, const P& p) {
+ typedef typename SimilarTypeTraits<P>::Type Type;
+ ParamTraits<Type>::Write(m, static_cast<const Type& >(p));
+}
+
+template <class P>
+static inline bool WARN_UNUSED_RESULT ReadParam(const base::Pickle* m,
+ base::PickleIterator* iter,
+ P* p) {
+ typedef typename SimilarTypeTraits<P>::Type Type;
+ return ParamTraits<Type>::Read(m, iter, reinterpret_cast<Type* >(p));
+}
+
+template <class P>
+static inline void LogParam(const P& p, std::string* l) {
+ typedef typename SimilarTypeTraits<P>::Type Type;
+ ParamTraits<Type>::Log(static_cast<const Type& >(p), l);
+}
+
+// Primitive ParamTraits -------------------------------------------------------
+
+template <>
+struct ParamTraits<bool> {
+ typedef bool param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddBool();
+ }
+ static void Write(base::Pickle* m, const param_type& p) { m->WriteBool(p); }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return iter->ReadBool(r);
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<signed char> {
+ typedef signed char param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<unsigned char> {
+ typedef unsigned char param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<unsigned short> {
+ typedef unsigned short param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<int> {
+ typedef int param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddInt();
+ }
+ static void Write(base::Pickle* m, const param_type& p) { m->WriteInt(p); }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return iter->ReadInt(r);
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<unsigned int> {
+ typedef unsigned int param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddInt();
+ }
+ static void Write(base::Pickle* m, const param_type& p) { m->WriteInt(p); }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return iter->ReadInt(reinterpret_cast<int*>(r));
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+// long isn't safe to send over IPC because it's 4 bytes on 32 bit builds but
+// 8 bytes on 64 bit builds. So if a 32 bit and 64 bit process have a channel
+// that would cause problem.
+// We need to keep this on for a few configs:
+// 1) Windows because DWORD is typedef'd to it, which is fine because we have
+// very few IPCs that cross this boundary.
+// 2) We also need to keep it for Linux for two reasons: int64_t is typedef'd
+// to long, and gfx::PluginWindow is long and is used in one GPU IPC.
+// 3) Android 64 bit also has int64_t typedef'd to long.
+// Since we want to support Android 32<>64 bit IPC, as long as we don't have
+// these traits for 32 bit ARM then that'll catch any errors.
+#if defined(OS_WIN) || defined(OS_LINUX) || \
+ (defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS))
+template <>
+struct ParamTraits<long> {
+ typedef long param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddLong();
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ m->WriteLong(p);
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return iter->ReadLong(r);
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<unsigned long> {
+ typedef unsigned long param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddLong();
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ m->WriteLong(p);
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return iter->ReadLong(reinterpret_cast<long*>(r));
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+#endif
+
+template <>
+struct ParamTraits<long long> {
+ typedef long long param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddInt64();
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ m->WriteInt64(static_cast<int64_t>(p));
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return iter->ReadInt64(reinterpret_cast<int64_t*>(r));
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<unsigned long long> {
+ typedef unsigned long long param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddInt64();
+ }
+ static void Write(base::Pickle* m, const param_type& p) { m->WriteInt64(p); }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return iter->ReadInt64(reinterpret_cast<int64_t*>(r));
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+// Note that the IPC layer doesn't sanitize NaNs and +/- INF values. Clients
+// should be sure to check the sanity of these values after receiving them over
+// IPC.
+template <>
+struct IPC_EXPORT ParamTraits<float> {
+ typedef float param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddFloat();
+ }
+ static void Write(base::Pickle* m, const param_type& p) { m->WriteFloat(p); }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return iter->ReadFloat(r);
+ }
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<double> {
+ typedef double param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+// STL ParamTraits -------------------------------------------------------------
+
+template <>
+struct ParamTraits<std::string> {
+ typedef std::string param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddString(p);
+ }
+ static void Write(base::Pickle* m, const param_type& p) { m->WriteString(p); }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return iter->ReadString(r);
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<base::string16> {
+ typedef base::string16 param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddString16(p);
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ m->WriteString16(p);
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return iter->ReadString16(r);
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<std::vector<char> > {
+ typedef std::vector<char> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle*,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<std::vector<unsigned char> > {
+ typedef std::vector<unsigned char> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<std::vector<bool> > {
+ typedef std::vector<bool> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <class P>
+struct ParamTraits<std::vector<P>> {
+ typedef std::vector<P> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p.size()));
+ for (size_t i = 0; i < p.size(); i++)
+ GetParamSize(sizer, p[i]);
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.size()));
+ for (size_t i = 0; i < p.size(); i++)
+ WriteParam(m, p[i]);
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int size;
+ // ReadLength() checks for < 0 itself.
+ if (!iter->ReadLength(&size))
+ return false;
+ // Resizing beforehand is not safe, see BUG 1006367 for details.
+ if (INT_MAX / sizeof(P) <= static_cast<size_t>(size))
+ return false;
+ r->resize(size);
+ for (int i = 0; i < size; i++) {
+ if (!ReadParam(m, iter, &(*r)[i]))
+ return false;
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ for (size_t i = 0; i < p.size(); ++i) {
+ if (i != 0)
+ l->append(" ");
+ LogParam((p[i]), l);
+ }
+ }
+};
+
+template <class P>
+struct ParamTraits<std::set<P> > {
+ typedef std::set<P> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter)
+ GetParamSize(sizer, *iter);
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter)
+ WriteParam(m, *iter);
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int size;
+ if (!iter->ReadLength(&size))
+ return false;
+ for (int i = 0; i < size; ++i) {
+ P item;
+ if (!ReadParam(m, iter, &item))
+ return false;
+ r->insert(item);
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<std::set>");
+ }
+};
+
+template <class K, class V, class C, class A>
+struct ParamTraits<std::map<K, V, C, A> > {
+ typedef std::map<K, V, C, A> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter) {
+ GetParamSize(sizer, iter->first);
+ GetParamSize(sizer, iter->second);
+ }
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter) {
+ WriteParam(m, iter->first);
+ WriteParam(m, iter->second);
+ }
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int size;
+ if (!ReadParam(m, iter, &size) || size < 0)
+ return false;
+ for (int i = 0; i < size; ++i) {
+ K k;
+ if (!ReadParam(m, iter, &k))
+ return false;
+ V& value = (*r)[k];
+ if (!ReadParam(m, iter, &value))
+ return false;
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<std::map>");
+ }
+};
+
+template <class A, class B>
+struct ParamTraits<std::pair<A, B> > {
+ typedef std::pair<A, B> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, p.first);
+ GetParamSize(sizer, p.second);
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, p.first);
+ WriteParam(m, p.second);
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return ReadParam(m, iter, &r->first) && ReadParam(m, iter, &r->second);
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.first, l);
+ l->append(", ");
+ LogParam(p.second, l);
+ l->append(")");
+ }
+};
+
+// IPC ParamTraits -------------------------------------------------------------
+template <>
+struct IPC_EXPORT ParamTraits<BrokerableAttachment::AttachmentId> {
+ typedef BrokerableAttachment::AttachmentId param_type;
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+// Base ParamTraits ------------------------------------------------------------
+
+template <>
+struct IPC_EXPORT ParamTraits<base::DictionaryValue> {
+ typedef base::DictionaryValue param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+#if defined(OS_POSIX)
+// FileDescriptors may be serialised over IPC channels on POSIX. On the
+// receiving side, the FileDescriptor is a valid duplicate of the file
+// descriptor which was transmitted: *it is not just a copy of the integer like
+// HANDLEs on Windows*. The only exception is if the file descriptor is < 0. In
+// this case, the receiving end will see a value of -1. *Zero is a valid file
+// descriptor*.
+//
+// The received file descriptor will have the |auto_close| flag set to true. The
+// code which handles the message is responsible for taking ownership of it.
+// File descriptors are OS resources and must be closed when no longer needed.
+//
+// When sending a file descriptor, the file descriptor must be valid at the time
+// of transmission. Since transmission is not synchronous, one should consider
+// dup()ing any file descriptors to be transmitted and setting the |auto_close|
+// flag, which causes the file descriptor to be closed after writing.
+template<>
+struct IPC_EXPORT ParamTraits<base::FileDescriptor> {
+ typedef base::FileDescriptor param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+#endif // defined(OS_POSIX)
+
+#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
+template <>
+struct IPC_EXPORT ParamTraits<base::SharedMemoryHandle> {
+ typedef base::SharedMemoryHandle param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+#endif // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
+
+template <>
+struct IPC_EXPORT ParamTraits<base::FilePath> {
+ typedef base::FilePath param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<base::ListValue> {
+ typedef base::ListValue param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<base::NullableString16> {
+ typedef base::NullableString16 param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<base::File::Info> {
+ typedef base::File::Info param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct SimilarTypeTraits<base::File::Error> {
+ typedef int Type;
+};
+
+#if defined(OS_WIN)
+template <>
+struct SimilarTypeTraits<HWND> {
+ typedef HANDLE Type;
+};
+#endif // defined(OS_WIN)
+
+template <>
+struct IPC_EXPORT ParamTraits<base::Time> {
+ typedef base::Time param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<base::TimeDelta> {
+ typedef base::TimeDelta param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<base::TimeTicks> {
+ typedef base::TimeTicks param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<std::tuple<>> {
+ typedef std::tuple<> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {}
+ static void Write(base::Pickle* m, const param_type& p) {}
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ }
+};
+
+template <class A>
+struct ParamTraits<std::tuple<A>> {
+ typedef std::tuple<A> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, std::get<0>(p));
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, std::get<0>(p));
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return ReadParam(m, iter, &std::get<0>(*r));
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(std::get<0>(p), l);
+ }
+};
+
+template <class A, class B>
+struct ParamTraits<std::tuple<A, B>> {
+ typedef std::tuple<A, B> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, std::get<0>(p));
+ GetParamSize(sizer, std::get<1>(p));
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, std::get<0>(p));
+ WriteParam(m, std::get<1>(p));
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return (ReadParam(m, iter, &std::get<0>(*r)) &&
+ ReadParam(m, iter, &std::get<1>(*r)));
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(std::get<0>(p), l);
+ l->append(", ");
+ LogParam(std::get<1>(p), l);
+ }
+};
+
+template <class A, class B, class C>
+struct ParamTraits<std::tuple<A, B, C>> {
+ typedef std::tuple<A, B, C> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, std::get<0>(p));
+ GetParamSize(sizer, std::get<1>(p));
+ GetParamSize(sizer, std::get<2>(p));
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, std::get<0>(p));
+ WriteParam(m, std::get<1>(p));
+ WriteParam(m, std::get<2>(p));
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return (ReadParam(m, iter, &std::get<0>(*r)) &&
+ ReadParam(m, iter, &std::get<1>(*r)) &&
+ ReadParam(m, iter, &std::get<2>(*r)));
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(std::get<0>(p), l);
+ l->append(", ");
+ LogParam(std::get<1>(p), l);
+ l->append(", ");
+ LogParam(std::get<2>(p), l);
+ }
+};
+
+template <class A, class B, class C, class D>
+struct ParamTraits<std::tuple<A, B, C, D>> {
+ typedef std::tuple<A, B, C, D> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, std::get<0>(p));
+ GetParamSize(sizer, std::get<1>(p));
+ GetParamSize(sizer, std::get<2>(p));
+ GetParamSize(sizer, std::get<3>(p));
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, std::get<0>(p));
+ WriteParam(m, std::get<1>(p));
+ WriteParam(m, std::get<2>(p));
+ WriteParam(m, std::get<3>(p));
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return (ReadParam(m, iter, &std::get<0>(*r)) &&
+ ReadParam(m, iter, &std::get<1>(*r)) &&
+ ReadParam(m, iter, &std::get<2>(*r)) &&
+ ReadParam(m, iter, &std::get<3>(*r)));
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(std::get<0>(p), l);
+ l->append(", ");
+ LogParam(std::get<1>(p), l);
+ l->append(", ");
+ LogParam(std::get<2>(p), l);
+ l->append(", ");
+ LogParam(std::get<3>(p), l);
+ }
+};
+
+template <class A, class B, class C, class D, class E>
+struct ParamTraits<std::tuple<A, B, C, D, E>> {
+ typedef std::tuple<A, B, C, D, E> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, std::get<0>(p));
+ GetParamSize(sizer, std::get<1>(p));
+ GetParamSize(sizer, std::get<2>(p));
+ GetParamSize(sizer, std::get<3>(p));
+ GetParamSize(sizer, std::get<4>(p));
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, std::get<0>(p));
+ WriteParam(m, std::get<1>(p));
+ WriteParam(m, std::get<2>(p));
+ WriteParam(m, std::get<3>(p));
+ WriteParam(m, std::get<4>(p));
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ return (ReadParam(m, iter, &std::get<0>(*r)) &&
+ ReadParam(m, iter, &std::get<1>(*r)) &&
+ ReadParam(m, iter, &std::get<2>(*r)) &&
+ ReadParam(m, iter, &std::get<3>(*r)) &&
+ ReadParam(m, iter, &std::get<4>(*r)));
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(std::get<0>(p), l);
+ l->append(", ");
+ LogParam(std::get<1>(p), l);
+ l->append(", ");
+ LogParam(std::get<2>(p), l);
+ l->append(", ");
+ LogParam(std::get<3>(p), l);
+ l->append(", ");
+ LogParam(std::get<4>(p), l);
+ }
+};
+
+template<class P>
+struct ParamTraits<ScopedVector<P> > {
+ typedef ScopedVector<P> param_type;
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.size()));
+ for (size_t i = 0; i < p.size(); i++)
+ WriteParam(m, *p[i]);
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int size = 0;
+ if (!iter->ReadLength(&size))
+ return false;
+ if (INT_MAX/sizeof(P) <= static_cast<size_t>(size))
+ return false;
+ r->resize(size);
+ for (int i = 0; i < size; i++) {
+ (*r)[i] = new P();
+ if (!ReadParam(m, iter, (*r)[i]))
+ return false;
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ for (size_t i = 0; i < p.size(); ++i) {
+ if (i != 0)
+ l->append(" ");
+ LogParam(*p[i], l);
+ }
+ }
+};
+
+template <class P, size_t stack_capacity>
+struct ParamTraits<base::StackVector<P, stack_capacity> > {
+ typedef base::StackVector<P, stack_capacity> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p->size()));
+ for (size_t i = 0; i < p->size(); i++)
+ GetParamSize(sizer, p[i]);
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p->size()));
+ for (size_t i = 0; i < p->size(); i++)
+ WriteParam(m, p[i]);
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int size;
+ // ReadLength() checks for < 0 itself.
+ if (!iter->ReadLength(&size))
+ return false;
+ // Sanity check for the vector size.
+ if (INT_MAX / sizeof(P) <= static_cast<size_t>(size))
+ return false;
+ P value;
+ for (int i = 0; i < size; i++) {
+ if (!ReadParam(m, iter, &value))
+ return false;
+ (*r)->push_back(value);
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ for (size_t i = 0; i < p->size(); ++i) {
+ if (i != 0)
+ l->append(" ");
+ LogParam((p[i]), l);
+ }
+ }
+};
+
+template <typename NormalMap,
+ int kArraySize,
+ typename EqualKey,
+ typename MapInit>
+struct ParamTraits<base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> > {
+ typedef base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> param_type;
+ typedef typename param_type::key_type K;
+ typedef typename param_type::data_type V;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter) {
+ GetParamSize(sizer, iter->first);
+ GetParamSize(sizer, iter->second);
+ }
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter) {
+ WriteParam(m, iter->first);
+ WriteParam(m, iter->second);
+ }
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ int size;
+ if (!iter->ReadLength(&size))
+ return false;
+ for (int i = 0; i < size; ++i) {
+ K key;
+ if (!ReadParam(m, iter, &key))
+ return false;
+ V& value = (*r)[key];
+ if (!ReadParam(m, iter, &value))
+ return false;
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<base::SmallMap>");
+ }
+};
+
+template <class P>
+struct ParamTraits<std::unique_ptr<P>> {
+ typedef std::unique_ptr<P> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ bool valid = !!p;
+ GetParamSize(sizer, valid);
+ if (valid)
+ GetParamSize(sizer, *p);
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ bool valid = !!p;
+ WriteParam(m, valid);
+ if (valid)
+ WriteParam(m, *p);
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ bool valid = false;
+ if (!ReadParam(m, iter, &valid))
+ return false;
+
+ if (!valid) {
+ r->reset();
+ return true;
+ }
+
+ param_type temp(new P());
+ if (!ReadParam(m, iter, temp.get()))
+ return false;
+
+ r->swap(temp);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ if (p)
+ LogParam(*p, l);
+ else
+ l->append("NULL");
+ }
+};
+
+template <class P>
+struct ParamTraits<base::Optional<P>> {
+ typedef base::Optional<P> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ const bool is_set = static_cast<bool>(p);
+ GetParamSize(sizer, is_set);
+ if (is_set)
+ GetParamSize(sizer, p.value());
+ }
+ static void Write(base::Pickle* m, const param_type& p) {
+ const bool is_set = static_cast<bool>(p);
+ WriteParam(m, is_set);
+ if (is_set)
+ WriteParam(m, p.value());
+ }
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ bool is_set = false;
+ if (!iter->ReadBool(&is_set))
+ return false;
+ if (is_set) {
+ P value;
+ if (!ReadParam(m, iter, &value))
+ return false;
+ *r = std::move(value);
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ if (p)
+ LogParam(p.value(), l);
+ else
+ l->append("(unset)");
+ }
+};
+
+// IPC types ParamTraits -------------------------------------------------------
+
+// A ChannelHandle is basically a platform-inspecific wrapper around the
+// fact that IPC endpoints are handled specially on POSIX. See above comments
+// on FileDescriptor for more background.
+template<>
+struct IPC_EXPORT ParamTraits<IPC::ChannelHandle> {
+ typedef ChannelHandle param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<LogData> {
+ typedef LogData param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<Message> {
+ static void Write(base::Pickle* m, const Message& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ Message* r);
+ static void Log(const Message& p, std::string* l);
+};
+
+// Windows ParamTraits ---------------------------------------------------------
+
+#if defined(OS_WIN)
+template <>
+struct IPC_EXPORT ParamTraits<HANDLE> {
+ typedef HANDLE param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<LOGFONT> {
+ typedef LOGFONT param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<MSG> {
+ typedef MSG param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+#endif // defined(OS_WIN)
+
+//-----------------------------------------------------------------------------
+// Generic message subclasses
+
+// defined in ipc_logging.cc
+IPC_EXPORT void GenerateLogData(const std::string& channel,
+ const Message& message,
+ LogData* data, bool get_params);
+
+
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+inline void AddOutputParamsToLog(const Message* msg, std::string* l) {
+ const std::string& output_params = msg->output_params();
+ if (!l->empty() && !output_params.empty())
+ l->append(", ");
+
+ l->append(output_params);
+}
+
+template <class ReplyParamType>
+inline void LogReplyParamsToMessage(const ReplyParamType& reply_params,
+ const Message* msg) {
+ if (msg->received_time() != 0) {
+ std::string output_params;
+ LogParam(reply_params, &output_params);
+ msg->set_output_params(output_params);
+ }
+}
+
+inline void ConnectMessageAndReply(const Message* msg, Message* reply) {
+ if (msg->sent_time()) {
+ // Don't log the sync message after dispatch, as we don't have the
+ // output parameters at that point. Instead, save its data and log it
+ // with the outgoing reply message when it's sent.
+ LogData* data = new LogData;
+ GenerateLogData("", *msg, data, true);
+ msg->set_dont_log();
+ reply->set_sync_log_data(data);
+ }
+}
+#else
+inline void AddOutputParamsToLog(const Message* msg, std::string* l) {}
+
+template <class ReplyParamType>
+inline void LogReplyParamsToMessage(const ReplyParamType& reply_params,
+ const Message* msg) {}
+
+inline void ConnectMessageAndReply(const Message* msg, Message* reply) {}
+#endif
+
+} // namespace IPC
+
+#endif // IPC_IPC_MESSAGE_UTILS_H_
diff --git a/ipc/ipc_mojo_handle_attachment.cc b/ipc/ipc_mojo_handle_attachment.cc
new file mode 100644
index 0000000..819a12b
--- /dev/null
+++ b/ipc/ipc_mojo_handle_attachment.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2015 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 "ipc/ipc_mojo_handle_attachment.h"
+
+#include <utility>
+
+#include "build/build_config.h"
+
+namespace IPC {
+namespace internal {
+
+MojoHandleAttachment::MojoHandleAttachment(mojo::ScopedHandle handle)
+ : handle_(std::move(handle)) {}
+
+MojoHandleAttachment::~MojoHandleAttachment() {
+}
+
+MessageAttachment::Type MojoHandleAttachment::GetType() const {
+ return TYPE_MOJO_HANDLE;
+}
+
+#if defined(OS_POSIX)
+base::PlatformFile MojoHandleAttachment::TakePlatformFile() {
+ NOTREACHED();
+ return base::kInvalidPlatformFile;
+}
+#endif // OS_POSIX
+
+mojo::ScopedHandle MojoHandleAttachment::TakeHandle() {
+ return std::move(handle_);
+}
+
+} // namespace internal
+} // namespace IPC
diff --git a/ipc/ipc_mojo_handle_attachment.h b/ipc/ipc_mojo_handle_attachment.h
new file mode 100644
index 0000000..6aa1888
--- /dev/null
+++ b/ipc/ipc_mojo_handle_attachment.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2015 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 IPC_IPC_MOJO_HANDLE_ATTACHMENT_H_
+#define IPC_IPC_MOJO_HANDLE_ATTACHMENT_H_
+
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_message_attachment.h"
+#include "mojo/public/cpp/system/handle.h"
+
+namespace IPC {
+
+namespace internal {
+
+// A MessageAttachment that holds a MojoHandle.
+// This can hold any type of transferrable Mojo handle (i.e. message pipe, data
+// pipe, etc), but the receiver is expected to know what type of handle to
+// expect.
+class IPC_EXPORT MojoHandleAttachment : public MessageAttachment {
+ public:
+ explicit MojoHandleAttachment(mojo::ScopedHandle handle);
+
+ Type GetType() const override;
+
+#if defined(OS_POSIX)
+ // Should not be called.
+ base::PlatformFile TakePlatformFile() override;
+#endif // OS_POSIX
+
+ // Returns the owning handle transferring the ownership.
+ mojo::ScopedHandle TakeHandle();
+
+ private:
+ ~MojoHandleAttachment() override;
+ mojo::ScopedHandle handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoHandleAttachment);
+};
+
+} // namespace internal
+} // namespace IPC
+
+#endif // IPC_IPC_MOJO_HANDLE_ATTACHMENT_H_
diff --git a/ipc/ipc_mojo_message_helper.cc b/ipc/ipc_mojo_message_helper.cc
new file mode 100644
index 0000000..8f86945
--- /dev/null
+++ b/ipc/ipc_mojo_message_helper.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2015 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 "ipc/ipc_mojo_message_helper.h"
+
+#include <utility>
+
+#include "ipc/ipc_mojo_handle_attachment.h"
+
+namespace IPC {
+
+// static
+bool MojoMessageHelper::WriteMessagePipeTo(
+ base::Pickle* message,
+ mojo::ScopedMessagePipeHandle handle) {
+ message->WriteAttachment(new internal::MojoHandleAttachment(
+ mojo::ScopedHandle::From(std::move(handle))));
+ return true;
+}
+
+// static
+bool MojoMessageHelper::ReadMessagePipeFrom(
+ const base::Pickle* message,
+ base::PickleIterator* iter,
+ mojo::ScopedMessagePipeHandle* handle) {
+ scoped_refptr<base::Pickle::Attachment> attachment;
+ if (!message->ReadAttachment(iter, &attachment)) {
+ LOG(ERROR) << "Failed to read attachment for message pipe.";
+ return false;
+ }
+
+ MessageAttachment::Type type =
+ static_cast<MessageAttachment*>(attachment.get())->GetType();
+ if (type != MessageAttachment::TYPE_MOJO_HANDLE) {
+ LOG(ERROR) << "Unxpected attachment type:" << type;
+ return false;
+ }
+
+ handle->reset(mojo::MessagePipeHandle(
+ static_cast<internal::MojoHandleAttachment*>(attachment.get())
+ ->TakeHandle()
+ .release()
+ .value()));
+ return true;
+}
+
+MojoMessageHelper::MojoMessageHelper() {
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_mojo_message_helper.h b/ipc/ipc_mojo_message_helper.h
new file mode 100644
index 0000000..4a71b5c
--- /dev/null
+++ b/ipc/ipc_mojo_message_helper.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2015 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 IPC_IPC_MOJO_MESSAGE_HELPER_H_
+#define IPC_IPC_MOJO_MESSAGE_HELPER_H_
+
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_message.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace IPC {
+
+// Reads and writes |mojo::MessagePipe| from/to |Message|.
+class IPC_EXPORT MojoMessageHelper {
+ public:
+ static bool WriteMessagePipeTo(base::Pickle* message,
+ mojo::ScopedMessagePipeHandle handle);
+ static bool ReadMessagePipeFrom(const base::Pickle* message,
+ base::PickleIterator* iter,
+ mojo::ScopedMessagePipeHandle* handle);
+
+ private:
+ MojoMessageHelper();
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_MOJO_MESSAGE_HELPER_H_
diff --git a/ipc/ipc_mojo_param_traits.cc b/ipc/ipc_mojo_param_traits.cc
new file mode 100644
index 0000000..189af35
--- /dev/null
+++ b/ipc/ipc_mojo_param_traits.cc
@@ -0,0 +1,50 @@
+// Copyright 2015 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 "ipc/ipc_mojo_param_traits.h"
+
+#include "ipc/ipc_message_utils.h"
+#include "ipc/ipc_mojo_message_helper.h"
+
+namespace IPC {
+
+void ParamTraits<mojo::MessagePipeHandle>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, p.is_valid());
+ if (p.is_valid())
+ sizer->AddAttachment();
+}
+
+void ParamTraits<mojo::MessagePipeHandle>::Write(base::Pickle* m,
+ const param_type& p) {
+ WriteParam(m, p.is_valid());
+ if (p.is_valid())
+ MojoMessageHelper::WriteMessagePipeTo(m, mojo::ScopedMessagePipeHandle(p));
+}
+
+bool ParamTraits<mojo::MessagePipeHandle>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ bool is_valid;
+ if (!ReadParam(m, iter, &is_valid))
+ return false;
+ if (!is_valid)
+ return true;
+
+ mojo::ScopedMessagePipeHandle handle;
+ if (!MojoMessageHelper::ReadMessagePipeFrom(m, iter, &handle))
+ return false;
+ DCHECK(handle.is_valid());
+ *r = handle.release();
+ return true;
+}
+
+void ParamTraits<mojo::MessagePipeHandle>::Log(const param_type& p,
+ std::string* l) {
+ l->append("mojo::MessagePipeHandle(");
+ LogParam(p.value(), l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_mojo_param_traits.h b/ipc/ipc_mojo_param_traits.h
new file mode 100644
index 0000000..39be43e
--- /dev/null
+++ b/ipc/ipc_mojo_param_traits.h
@@ -0,0 +1,34 @@
+// Copyright 2015 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 IPC_IPC_MOJO_PARAM_TRAITS_H_
+#define IPC_IPC_MOJO_PARAM_TRAITS_H_
+
+#include <string>
+
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_param_traits.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace base {
+class Pickle;
+class PickleIterator;
+class PickleSizer;
+}
+
+namespace IPC {
+
+template <>
+struct IPC_EXPORT ParamTraits<mojo::MessagePipeHandle> {
+ typedef mojo::MessagePipeHandle param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m, base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_MOJO_PARAM_TRAITS_H_
diff --git a/ipc/ipc_param_traits.h b/ipc/ipc_param_traits.h
new file mode 100644
index 0000000..45e975c
--- /dev/null
+++ b/ipc/ipc_param_traits.h
@@ -0,0 +1,23 @@
+// 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 IPC_IPC_PARAM_TRAITS_H_
+#define IPC_IPC_PARAM_TRAITS_H_
+
+// Our IPC system uses the following partially specialized header to define how
+// a data type is read, written and logged in the IPC system.
+
+namespace IPC {
+
+template <class P> struct ParamTraits {
+};
+
+template <class P>
+struct SimilarTypeTraits {
+ typedef P Type;
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_PARAM_TRAITS_H_
diff --git a/ipc/ipc_platform_file_attachment_posix.cc b/ipc/ipc_platform_file_attachment_posix.cc
new file mode 100644
index 0000000..b130ab2
--- /dev/null
+++ b/ipc/ipc_platform_file_attachment_posix.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2015 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 "ipc/ipc_platform_file_attachment_posix.h"
+
+#include <utility>
+
+namespace IPC {
+namespace internal {
+
+PlatformFileAttachment::PlatformFileAttachment(base::PlatformFile file)
+ : file_(file) {
+}
+
+PlatformFileAttachment::PlatformFileAttachment(base::ScopedFD file)
+ : file_(file.get()), owning_(std::move(file)) {}
+
+PlatformFileAttachment::~PlatformFileAttachment() {
+}
+
+MessageAttachment::Type PlatformFileAttachment::GetType() const {
+ return TYPE_PLATFORM_FILE;
+}
+
+base::PlatformFile PlatformFileAttachment::TakePlatformFile() {
+ ignore_result(owning_.release());
+ return file_;
+}
+
+base::PlatformFile GetPlatformFile(
+ scoped_refptr<MessageAttachment> attachment) {
+ DCHECK_EQ(attachment->GetType(), MessageAttachment::TYPE_PLATFORM_FILE);
+ return static_cast<PlatformFileAttachment*>(attachment.get())->file();
+}
+
+} // namespace internal
+} // namespace IPC
diff --git a/ipc/ipc_platform_file_attachment_posix.h b/ipc/ipc_platform_file_attachment_posix.h
new file mode 100644
index 0000000..d1eff60
--- /dev/null
+++ b/ipc/ipc_platform_file_attachment_posix.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2015 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 IPC_IPC_PLATFORM_FILE_ATTACHMENT_H_
+#define IPC_IPC_PLATFORM_FILE_ATTACHMENT_H_
+
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_message_attachment.h"
+
+namespace IPC {
+namespace internal {
+
+// A platform file that is sent over |Channel| as a part of |Message|.
+// PlatformFileAttachment optionally owns the file and |owning_| is set in that
+// case. Also, |file_| is not cleared even after the ownership is taken.
+// Some old clients require this strange behavior.
+class IPC_EXPORT PlatformFileAttachment : public MessageAttachment {
+ public:
+ // Non-owning constructor
+ explicit PlatformFileAttachment(base::PlatformFile file);
+ // Owning constructor
+ explicit PlatformFileAttachment(base::ScopedFD file);
+
+ Type GetType() const override;
+ base::PlatformFile TakePlatformFile() override;
+
+ base::PlatformFile file() const { return file_; }
+ bool Owns() const { return owning_.is_valid(); }
+
+ private:
+ ~PlatformFileAttachment() override;
+
+ base::PlatformFile file_;
+ base::ScopedFD owning_;
+};
+
+base::PlatformFile GetPlatformFile(scoped_refptr<MessageAttachment> attachment);
+
+} // namespace internal
+} // namespace IPC
+
+#endif // IPC_IPC_PLATFORM_FILE_ATTACHMENT_H_
diff --git a/ipc/ipc_sync_message.h b/ipc/ipc_sync_message.h
new file mode 100644
index 0000000..ed5204f
--- /dev/null
+++ b/ipc/ipc_sync_message.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 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 IPC_IPC_SYNC_MESSAGE_H_
+#define IPC_IPC_SYNC_MESSAGE_H_
+
+#include <stdint.h>
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include <memory>
+#include <string>
+
+#include "build/build_config.h"
+#include "ipc/ipc_message.h"
+
+namespace IPC {
+
+class MessageReplyDeserializer;
+class MojoEvent;
+
+class IPC_EXPORT SyncMessage : public Message {
+ public:
+ SyncMessage(int32_t routing_id,
+ uint32_t type,
+ PriorityValue priority,
+ MessageReplyDeserializer* deserializer);
+ ~SyncMessage() override;
+
+ // Call this to get a deserializer for the output parameters.
+ // Note that this can only be called once, and the caller is responsible
+ // for deleting the deserializer when they're done.
+ MessageReplyDeserializer* GetReplyDeserializer();
+
+ // If this message can cause the receiver to block while waiting for user
+ // input (i.e. by calling MessageBox), then the caller needs to pump window
+ // messages and dispatch asynchronous messages while waiting for the reply.
+ // This call enables message pumping behavior while waiting for a reply to
+ // this message.
+ void EnableMessagePumping() {
+ header()->flags |= PUMPING_MSGS_BIT;
+ }
+
+ // Indicates whether window messages should be pumped while waiting for a
+ // reply to this message.
+ bool ShouldPumpMessages() const {
+ return (header()->flags & PUMPING_MSGS_BIT) != 0;
+ }
+
+ // Returns true if the message is a reply to the given request id.
+ static bool IsMessageReplyTo(const Message& msg, int request_id);
+
+ // Given a reply message, returns an iterator to the beginning of the data
+ // (i.e. skips over the synchronous specific data).
+ static base::PickleIterator GetDataIterator(const Message* msg);
+
+ // Given a synchronous message (or its reply), returns its id.
+ static int GetMessageId(const Message& msg);
+
+ // Generates a reply message to the given message.
+ static Message* GenerateReply(const Message* msg);
+
+ private:
+ struct SyncHeader {
+ // unique ID (unique per sender)
+ int message_id;
+ };
+
+ static bool ReadSyncHeader(const Message& msg, SyncHeader* header);
+ static bool WriteSyncHeader(Message* msg, const SyncHeader& header);
+
+ std::unique_ptr<MessageReplyDeserializer> deserializer_;
+};
+
+// Used to deserialize parameters from a reply to a synchronous message
+class IPC_EXPORT MessageReplyDeserializer {
+ public:
+ virtual ~MessageReplyDeserializer() {}
+ bool SerializeOutputParameters(const Message& msg);
+ private:
+ // Derived classes need to implement this, using the given iterator (which
+ // is skipped past the header for synchronous messages).
+ virtual bool SerializeOutputParameters(const Message& msg,
+ base::PickleIterator iter) = 0;
+};
+
+// When sending a synchronous message, this structure contains an object
+// that knows how to deserialize the response.
+struct PendingSyncMsg {
+ PendingSyncMsg(int id, MessageReplyDeserializer* d, MojoEvent* e)
+ : id(id), deserializer(d), done_event(e), send_result(false) { }
+
+ int id;
+ MessageReplyDeserializer* deserializer;
+ MojoEvent* done_event;
+ bool send_result;
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_SYNC_MESSAGE_H_
diff --git a/ipc/placeholder_brokerable_attachment.cc b/ipc/placeholder_brokerable_attachment.cc
new file mode 100644
index 0000000..e64e398
--- /dev/null
+++ b/ipc/placeholder_brokerable_attachment.cc
@@ -0,0 +1,14 @@
+// Copyright 2015 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 "ipc/placeholder_brokerable_attachment.h"
+
+namespace IPC {
+
+BrokerableAttachment::BrokerableType
+PlaceholderBrokerableAttachment::GetBrokerableType() const {
+ return PLACEHOLDER;
+}
+
+} // namespace IPC
diff --git a/ipc/placeholder_brokerable_attachment.h b/ipc/placeholder_brokerable_attachment.h
new file mode 100644
index 0000000..a8b08ef
--- /dev/null
+++ b/ipc/placeholder_brokerable_attachment.h
@@ -0,0 +1,29 @@
+// Copyright 2015 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 IPC_PLACEHOLDER_BROKERABLE_ATTACHMENT_H_
+#define IPC_PLACEHOLDER_BROKERABLE_ATTACHMENT_H_
+
+#include "base/macros.h"
+#include "ipc/brokerable_attachment.h"
+#include "ipc/ipc_export.h"
+
+namespace IPC {
+
+// This subclass of BrokerableAttachment has an AttachmentId, and nothing else.
+// It is intended to be replaced by the attachment broker.
+class IPC_EXPORT PlaceholderBrokerableAttachment : public BrokerableAttachment {
+ public:
+ PlaceholderBrokerableAttachment(const AttachmentId& id)
+ : BrokerableAttachment(id){};
+ BrokerableType GetBrokerableType() const override;
+
+ protected:
+ ~PlaceholderBrokerableAttachment() override{};
+ DISALLOW_COPY_AND_ASSIGN(PlaceholderBrokerableAttachment);
+};
+
+} // namespace IPC
+
+#endif // IPC_PLACEHOLDER_BROKERABLE_ATTACHMENT_H_