#ifndef IPC_IPC_MESSAGE_TEMPLATES_H_
#define IPC_IPC_MESSAGE_TEMPLATES_H_
#include <stdint.h>
#include <tuple>
#include <type_traits>
#include <utility>
#include "base/check.h"
#include "base/notreached.h"
#include "base/trace_event/trace_event.h"
#include "base/tuple.h"
#include "build/build_config.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_sync_message.h"
namespace IPC {
template <typename Tuple, size_t... Ns>
auto TupleForwardImpl(Tuple&& tuple, std::index_sequence<Ns...>) -> decltype(
std::forward_as_tuple(std::get<Ns>(std::forward<Tuple>(tuple))...)) {
return std::forward_as_tuple(std::get<Ns>(std::forward<Tuple>(tuple))...);
}
template <typename Tuple>
auto TupleForward(Tuple&& tuple) -> decltype(TupleForwardImpl(
std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>())) {
return TupleForwardImpl(
std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>());
}
template <typename ObjT, typename Method, typename P, typename Tuple>
void DispatchToMethod(ObjT* obj, Method method, P*, Tuple&& tuple) {
base::DispatchToMethod(obj, method, std::forward<Tuple>(tuple));
}
template <typename ObjT,
typename Method,
typename P,
typename Tuple,
size_t... Ns>
void DispatchToMethodImpl(ObjT* obj,
Method method,
P* parameter,
Tuple&& tuple,
std::index_sequence<Ns...>) {
(obj->*method)(parameter, std::get<Ns>(std::forward<Tuple>(tuple))...);
}
template <typename ObjT, typename P, typename... Args, typename Tuple>
std::enable_if_t<sizeof...(Args) == std::tuple_size<std::decay_t<Tuple>>::value>
DispatchToMethod(ObjT* obj,
void (ObjT::*method)(P*, Args...),
P* parameter,
Tuple&& tuple) {
constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
DispatchToMethodImpl(obj, method, parameter, std::forward<Tuple>(tuple),
std::make_index_sequence<size>());
}
enum class MessageKind {
CONTROL,
ROUTED,
};
struct Routing {
explicit Routing(int32_t id) : id(id) {}
int32_t id;
};
#define IPC_MESSAGET_SFINAE(x) \
template <bool X = (x), typename std::enable_if<X, bool>::type = false>
template <typename Meta,
typename InTuple = typename Meta::InTuple,
typename OutTuple = typename Meta::OutTuple>
class MessageT;
template <typename Meta, typename... Ins>
class MessageT<Meta, std::tuple<Ins...>, void> : public Message {
public:
using Param = std::tuple<Ins...>;
enum { ID = Meta::ID };
using Schema = MessageT;
IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) {
DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
}
IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
MessageT(int32_t routing_id, const Ins&... ins)
: MessageT(Routing(routing_id), ins...) {
DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
}
static bool Read(const Message* msg, Param* p);
static void Log(std::string* name, const Message* msg, std::string* l);
template <class T, class S, class P, class Method>
static bool Dispatch(const Message* msg,
T* obj,
S* sender,
P* parameter,
Method func) {
TRACE_EVENT0("ipc", Meta::kName);
Param p;
if (Read(msg, &p)) {
DispatchToMethod(obj, func, parameter, std::move(p));
return true;
}
return false;
}
private:
MessageT(Routing routing, const Ins&... ins);
};
template <typename Meta, typename... Ins, typename... Outs>
class MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>
: public SyncMessage {
public:
using SendParam = std::tuple<Ins...>;
using ReplyParam = std::tuple<Outs...>;
enum { ID = Meta::ID };
using Schema = MessageT;
IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
MessageT(const Ins&... ins, Outs*... outs)
: MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) {
DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
}
IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs)
: MessageT(Routing(routing_id), ins..., outs...) {
DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
}
static bool ReadSendParam(const Message* msg, SendParam* p);
static bool ReadReplyParam(const Message* msg, ReplyParam* p);
static void WriteReplyParams(Message* reply, const Outs&... outs);
static void Log(std::string* name, const Message* msg, std::string* l);
template <class T, class S, class P, class Method>
static bool Dispatch(const Message* msg,
T* obj,
S* sender,
P* ,
Method func) {
TRACE_EVENT0("ipc", Meta::kName);
SendParam send_params;
bool ok = ReadSendParam(msg, &send_params);
Message* reply = SyncMessage::GenerateReply(msg);
if (!ok) {
NOTREACHED() << "Error deserializing message " << msg->type();
reply->set_reply_error();
sender->Send(reply);
return false;
}
ReplyParam reply_params;
base::DispatchToMethod(obj, func, std::move(send_params), &reply_params);
WriteParam(reply, reply_params);
LogReplyParamsToMessage(reply_params, msg);
sender->Send(reply);
return true;
}
#if BUILDFLAG(IS_OHOS)
template <class T, class S, class P, class Method>
static bool Dispatch_Param(const Message* msg,
T* obj,
S* sender,
P* parameter,
Method func) {
TRACE_EVENT0("ipc", Meta::kName);
SendParam send_params;
bool ok = ReadSendParam(msg, &send_params);
Message* reply = SyncMessage::GenerateReply(msg);
if (!ok) {
NOTREACHED() << "Error deserializing message " << msg->type();
reply->set_reply_error();
sender->Send(reply);
return false;
}
ReplyParam reply_params;
base::DispatchToMethod_Param(obj, func, std::move(send_params), parameter, &reply_params);
WriteParam(reply, reply_params);
LogReplyParamsToMessage(reply_params, msg);
sender->Send(reply);
return true;
}
#endif
template <class T, class P, class Method>
static bool DispatchDelayReply(const Message* msg,
T* obj,
P* ,
Method func) {
TRACE_EVENT0("ipc", Meta::kName);
SendParam send_params;
bool ok = ReadSendParam(msg, &send_params);
Message* reply = SyncMessage::GenerateReply(msg);
if (!ok) {
NOTREACHED() << "Error deserializing message " << msg->type();
reply->set_reply_error();
obj->Send(reply);
return false;
}
std::tuple<Message&> t = std::tie(*reply);
ConnectMessageAndReply(msg, reply);
base::DispatchToMethod(obj, func, std::move(send_params), &t);
return true;
}
template <class T, class P, class Method>
static bool DispatchWithParamDelayReply(const Message* msg,
T* obj,
P* parameter,
Method func) {
TRACE_EVENT0("ipc", Meta::kName);
SendParam send_params;
bool ok = ReadSendParam(msg, &send_params);
Message* reply = SyncMessage::GenerateReply(msg);
if (!ok) {
NOTREACHED() << "Error deserializing message " << msg->type();
reply->set_reply_error();
obj->Send(reply);
return false;
}
std::tuple<Message&> t = std::tie(*reply);
ConnectMessageAndReply(msg, reply);
std::tuple<P*> parameter_tuple(parameter);
base::DispatchToMethod(
obj, func,
std::tuple_cat(std::move(parameter_tuple), TupleForward(send_params)),
&t);
return true;
}
private:
MessageT(Routing routing, const Ins&... ins, Outs*... outs);
};
}
#if defined(IPC_MESSAGE_IMPL)
#include "ipc/ipc_message_templates_impl.h"
#endif
#endif