You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1082 lines
34 KiB
1082 lines
34 KiB
// 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 <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "base/component_export.h"
|
|
#include "base/containers/flat_map.h"
|
|
#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/platform_shared_memory_region.h"
|
|
#include "base/memory/read_only_shared_memory_region.h"
|
|
#include "base/memory/shared_memory_handle.h"
|
|
#include "base/memory/unsafe_shared_memory_region.h"
|
|
#include "base/memory/writable_shared_memory_region.h"
|
|
#include "base/numerics/safe_conversions.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/ipc_message_start.h"
|
|
#include "ipc/ipc_param_traits.h"
|
|
#include "ipc/ipc_sync_message.h"
|
|
|
|
#if defined(OS_ANDROID)
|
|
#include "base/android/scoped_hardware_buffer_handle.h"
|
|
#endif
|
|
|
|
namespace base {
|
|
class DictionaryValue;
|
|
class FilePath;
|
|
class ListValue;
|
|
class NullableString16;
|
|
class Time;
|
|
class TimeDelta;
|
|
class TimeTicks;
|
|
class UnguessableToken;
|
|
struct FileDescriptor;
|
|
}
|
|
|
|
namespace IPC {
|
|
|
|
struct ChannelHandle;
|
|
|
|
#if defined(OS_WIN)
|
|
class PlatformFileForTransit;
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// How we send IPC message logs across channels.
|
|
struct COMPONENT_EXPORT(IPC) 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;
|
|
};
|
|
|
|
// 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 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);
|
|
}
|
|
COMPONENT_EXPORT(IPC) static void Log(const param_type& p, std::string* l);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<signed char> {
|
|
typedef signed char 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<unsigned char> {
|
|
typedef unsigned char 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<unsigned short> {
|
|
typedef unsigned short 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);
|
|
};
|
|
|
|
template <>
|
|
struct ParamTraits<int> {
|
|
typedef int param_type;
|
|
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);
|
|
}
|
|
COMPONENT_EXPORT(IPC) static void Log(const param_type& p, std::string* l);
|
|
};
|
|
|
|
template <>
|
|
struct ParamTraits<unsigned int> {
|
|
typedef unsigned int param_type;
|
|
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));
|
|
}
|
|
COMPONENT_EXPORT(IPC) 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 and Fuchsia also have 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_FUCHSIA) || \
|
|
(defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS))
|
|
template <>
|
|
struct ParamTraits<long> {
|
|
typedef long param_type;
|
|
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);
|
|
}
|
|
COMPONENT_EXPORT(IPC) static void Log(const param_type& p, std::string* l);
|
|
};
|
|
|
|
template <>
|
|
struct ParamTraits<unsigned long> {
|
|
typedef unsigned long param_type;
|
|
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));
|
|
}
|
|
COMPONENT_EXPORT(IPC) static void Log(const param_type& p, std::string* l);
|
|
};
|
|
#endif
|
|
|
|
template <>
|
|
struct ParamTraits<long long> {
|
|
typedef long long param_type;
|
|
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));
|
|
}
|
|
COMPONENT_EXPORT(IPC) static void Log(const param_type& p, std::string* l);
|
|
};
|
|
|
|
template <>
|
|
struct ParamTraits<unsigned long long> {
|
|
typedef unsigned long long param_type;
|
|
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));
|
|
}
|
|
COMPONENT_EXPORT(IPC) 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 COMPONENT_EXPORT(IPC) ParamTraits<float> {
|
|
typedef float param_type;
|
|
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 COMPONENT_EXPORT(IPC) ParamTraits<double> {
|
|
typedef double 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);
|
|
};
|
|
|
|
template <class P, size_t Size>
|
|
struct ParamTraits<P[Size]> {
|
|
using param_type = P[Size];
|
|
static void Write(base::Pickle* m, const param_type& p) {
|
|
for (const P& element : p)
|
|
WriteParam(m, element);
|
|
}
|
|
static bool Read(const base::Pickle* m,
|
|
base::PickleIterator* iter,
|
|
param_type* r) {
|
|
for (P& element : *r) {
|
|
if (!ReadParam(m, iter, &element))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
static void Log(const param_type& p, std::string* l) {
|
|
l->append("[");
|
|
for (const P& element : p) {
|
|
if (&element != &p[0])
|
|
l->append(" ");
|
|
LogParam(element, l);
|
|
}
|
|
l->append("]");
|
|
}
|
|
};
|
|
|
|
// STL ParamTraits -------------------------------------------------------------
|
|
|
|
template <>
|
|
struct ParamTraits<std::string> {
|
|
typedef std::string param_type;
|
|
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);
|
|
}
|
|
COMPONENT_EXPORT(IPC) static void Log(const param_type& p, std::string* l);
|
|
};
|
|
|
|
template <>
|
|
struct ParamTraits<base::string16> {
|
|
typedef base::string16 param_type;
|
|
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);
|
|
}
|
|
COMPONENT_EXPORT(IPC) static void Log(const param_type& p, std::string* l);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<std::vector<char>> {
|
|
typedef std::vector<char> param_type;
|
|
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 COMPONENT_EXPORT(IPC) ParamTraits<std::vector<unsigned char>> {
|
|
typedef std::vector<unsigned char> 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<std::vector<bool>> {
|
|
typedef std::vector<bool> 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);
|
|
};
|
|
|
|
template <class P>
|
|
struct ParamTraits<std::vector<P>> {
|
|
typedef std::vector<P> param_type;
|
|
static void Write(base::Pickle* m, const param_type& p) {
|
|
WriteParam(m, base::checked_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 Write(base::Pickle* m, const param_type& p) {
|
|
WriteParam(m, base::checked_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 Write(base::Pickle* m, const param_type& p) {
|
|
WriteParam(m, base::checked_cast<int>(p.size()));
|
|
for (const auto& iter : p) {
|
|
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 K, class V, class C, class A>
|
|
struct ParamTraits<std::unordered_map<K, V, C, A>> {
|
|
typedef std::unordered_map<K, V, C, A> param_type;
|
|
static void Write(base::Pickle* m, const param_type& p) {
|
|
WriteParam(m, base::checked_cast<int>(p.size()));
|
|
for (const auto& iter : p) {
|
|
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::unordered_map>");
|
|
}
|
|
};
|
|
|
|
template <class A, class B>
|
|
struct ParamTraits<std::pair<A, B> > {
|
|
typedef std::pair<A, B> param_type;
|
|
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(")");
|
|
}
|
|
};
|
|
|
|
// Base ParamTraits ------------------------------------------------------------
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::DictionaryValue> {
|
|
typedef base::DictionaryValue 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);
|
|
};
|
|
|
|
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
|
// 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 COMPONENT_EXPORT(IPC) ParamTraits<base::FileDescriptor> {
|
|
typedef base::FileDescriptor 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);
|
|
};
|
|
#endif // defined(OS_POSIX) || defined(OS_FUCHSIA)
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::SharedMemoryHandle> {
|
|
typedef base::SharedMemoryHandle 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);
|
|
};
|
|
|
|
#if defined(OS_ANDROID)
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<AHardwareBuffer*> {
|
|
typedef AHardwareBuffer* 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);
|
|
};
|
|
#endif
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::ReadOnlySharedMemoryRegion> {
|
|
typedef base::ReadOnlySharedMemoryRegion 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::WritableSharedMemoryRegion> {
|
|
typedef base::WritableSharedMemoryRegion 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::UnsafeSharedMemoryRegion> {
|
|
typedef base::UnsafeSharedMemoryRegion 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC)
|
|
ParamTraits<base::subtle::PlatformSharedMemoryRegion> {
|
|
typedef base::subtle::PlatformSharedMemoryRegion 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC)
|
|
ParamTraits<base::subtle::PlatformSharedMemoryRegion::Mode> {
|
|
typedef base::subtle::PlatformSharedMemoryRegion::Mode 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);
|
|
};
|
|
|
|
#if defined(OS_WIN)
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<PlatformFileForTransit> {
|
|
typedef PlatformFileForTransit 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);
|
|
};
|
|
#endif // defined(OS_WIN)
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::FilePath> {
|
|
typedef base::FilePath 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::ListValue> {
|
|
typedef base::ListValue 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::NullableString16> {
|
|
typedef base::NullableString16 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::File::Info> {
|
|
typedef base::File::Info 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);
|
|
};
|
|
|
|
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 COMPONENT_EXPORT(IPC) ParamTraits<base::Time> {
|
|
typedef base::Time 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::TimeDelta> {
|
|
typedef base::TimeDelta 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::TimeTicks> {
|
|
typedef base::TimeTicks 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<base::UnguessableToken> {
|
|
typedef base::UnguessableToken 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);
|
|
};
|
|
|
|
template <>
|
|
struct ParamTraits<std::tuple<>> {
|
|
typedef std::tuple<> 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) {
|
|
return true;
|
|
}
|
|
static void Log(const param_type& p, std::string* l) {
|
|
}
|
|
};
|
|
|
|
template <typename T, int index, int count>
|
|
struct TupleParamTraitsHelper {
|
|
using Next = TupleParamTraitsHelper<T, index + 1, count>;
|
|
|
|
static void Write(base::Pickle* m, const T& p) {
|
|
WriteParam(m, std::get<index>(p));
|
|
Next::Write(m, p);
|
|
}
|
|
|
|
static bool Read(const base::Pickle* m, base::PickleIterator* iter, T* r) {
|
|
return ReadParam(m, iter, &std::get<index>(*r)) && Next::Read(m, iter, r);
|
|
}
|
|
|
|
static void Log(const T& p, std::string* l) {
|
|
LogParam(std::get<index>(p), l);
|
|
if (index < count - 1)
|
|
l->append(", ");
|
|
Next::Log(p, l);
|
|
}
|
|
};
|
|
|
|
template <typename T, int index>
|
|
struct TupleParamTraitsHelper<T, index, index> {
|
|
static void Write(base::Pickle* m, const T& p) {}
|
|
static bool Read(const base::Pickle* m, base::PickleIterator* iter, T* r) {
|
|
return true;
|
|
}
|
|
static void Log(const T& p, std::string* l) {}
|
|
};
|
|
|
|
template <typename... Args>
|
|
struct ParamTraits<std::tuple<Args...>> {
|
|
using param_type = std::tuple<Args...>;
|
|
using Helper =
|
|
TupleParamTraitsHelper<param_type, 0, std::tuple_size<param_type>::value>;
|
|
|
|
static void Write(base::Pickle* m, const param_type& p) {
|
|
Helper::Write(m, p);
|
|
}
|
|
|
|
static bool Read(const base::Pickle* m,
|
|
base::PickleIterator* iter,
|
|
param_type* r) {
|
|
return Helper::Read(m, iter, r);
|
|
}
|
|
|
|
static void Log(const param_type& p, std::string* l) { Helper::Log(p, 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 Write(base::Pickle* m, const param_type& p) {
|
|
WriteParam(m, base::checked_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::small_map<NormalMap, kArraySize, EqualKey, MapInit>> {
|
|
using param_type = base::small_map<NormalMap, kArraySize, EqualKey, MapInit>;
|
|
using K = typename param_type::key_type;
|
|
using V = typename param_type::data_type;
|
|
static void Write(base::Pickle* m, const param_type& p) {
|
|
WriteParam(m, base::checked_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::small_map>");
|
|
}
|
|
};
|
|
|
|
template <class Key, class Mapped, class Compare>
|
|
struct ParamTraits<base::flat_map<Key, Mapped, Compare>> {
|
|
using param_type = base::flat_map<Key, Mapped, Compare>;
|
|
static void Write(base::Pickle* m, const param_type& p) {
|
|
DCHECK(base::IsValueInRangeForNumericType<int>(p.size()));
|
|
WriteParam(m, base::checked_cast<int>(p.size()));
|
|
for (const auto& iter : p) {
|
|
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;
|
|
|
|
// Construct by creating in a vector and moving into the flat_map. Properly
|
|
// serialized flat_maps will be in-order so this will be O(n). Incorrectly
|
|
// serialized ones will still be handled properly.
|
|
std::vector<typename param_type::value_type> vect;
|
|
vect.resize(size);
|
|
for (int i = 0; i < size; ++i) {
|
|
if (!ReadParam(m, iter, &vect[i].first))
|
|
return false;
|
|
if (!ReadParam(m, iter, &vect[i].second))
|
|
return false;
|
|
}
|
|
|
|
*r = param_type(std::move(vect), base::KEEP_FIRST_OF_DUPES);
|
|
return true;
|
|
}
|
|
static void Log(const param_type& p, std::string* l) {
|
|
l->append("<base::flat_map>");
|
|
}
|
|
};
|
|
|
|
template <class P>
|
|
struct ParamTraits<std::unique_ptr<P>> {
|
|
typedef std::unique_ptr<P> param_type;
|
|
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 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 COMPONENT_EXPORT(IPC) ParamTraits<IPC::ChannelHandle> {
|
|
typedef ChannelHandle 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<LogData> {
|
|
typedef LogData 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) 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 COMPONENT_EXPORT(IPC) ParamTraits<HANDLE> {
|
|
typedef HANDLE 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);
|
|
};
|
|
|
|
template <>
|
|
struct COMPONENT_EXPORT(IPC) ParamTraits<MSG> {
|
|
typedef MSG 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);
|
|
};
|
|
#endif // defined(OS_WIN)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Generic message subclasses
|
|
|
|
// defined in ipc_logging.cc
|
|
COMPONENT_EXPORT(IPC)
|
|
void GenerateLogData(const Message& message, LogData* data, bool get_params);
|
|
|
|
#if BUILDFLAG(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_
|