blob: ddacf7f5aa7deda4a747681f88a2a84c714c3d31 [file] [log] [blame]
{%- import "interface_macros.tmpl" as interface_macros %}
{%- import "struct_macros.tmpl" as struct_macros %}
{%- set class_name = interface.name %}
{%- set proxy_name = interface.name ~ "Proxy" %}
{%- set namespace_as_string = "%s"|format(namespace|replace(".","::")) %}
{%- macro alloc_params(struct, params, message, description) %}
mojo::internal::SerializationContext serialization_context;
serialization_context.TakeHandlesFromMessage({{message}});
bool success = true;
{%- for param in struct.packed.packed_fields_in_ordinal_order %}
{{param.field.kind|cpp_wrapper_call_type}} p_{{param.field.name}}{};
{%- endfor %}
{{struct.name}}DataView input_data_view({{params}}, &serialization_context);
{{struct_macros.deserialize(struct, "input_data_view", "p_%s", "success")}}
if (!success) {
ReportValidationErrorForMessage(
{{message}},
mojo::internal::VALIDATION_ERROR_DESERIALIZATION_FAILED,
"{{description}} deserializer");
return false;
}
{%- endmacro %}
{%- macro pass_params(parameters) %}
{%- for param in parameters %}
std::move(p_{{param.name}})
{%- if not loop.last %}, {% endif %}
{%- endfor %}
{%- endmacro %}
{#--- Begin #}
const char {{class_name}}::Name_[] = "{{namespace}}.{{class_name}}";
{#--- Constants #}
{%- for constant in interface.constants %}
{%- if constant.kind|is_string_kind %}
const char {{interface.name}}::{{constant.name}}[] = {{constant|constant_value}};
{%- else %}
constexpr {{constant.kind|cpp_pod_type}} {{interface.name}}::{{constant.name}};
{%- endif %}
{%- endfor %}
{%- for method in interface.methods %}
{%- if method.sync %}
bool {{class_name}}::{{method.name}}({{interface_macros.declare_sync_method_params("", method)}}) {
NOTREACHED();
return false;
}
{%- endif %}
{%- endfor %}
{#--- ForwardToCallback definition #}
{%- for method in interface.methods -%}
{%- if method.response_parameters != None %}
{%- if method.sync %}
class {{class_name}}_{{method.name}}_HandleSyncResponse
: public mojo::MessageReceiver {
public:
{{class_name}}_{{method.name}}_HandleSyncResponse(
bool* result
{%- for param in method.response_parameters -%}
, {{param.kind|cpp_wrapper_call_type}}* out_{{param.name}}
{%- endfor %})
: result_(result)
{%- for param in method.response_parameters -%}
, out_{{param.name}}_(out_{{param.name}})
{%- endfor %} {
DCHECK(!*result_);
}
bool Accept(mojo::Message* message) override;
private:
bool* result_;
{%- for param in method.response_parameters %}
{{param.kind|cpp_wrapper_call_type}}* out_{{param.name}}_;
{%- endfor -%}
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_HandleSyncResponse);
};
{%- endif %}
class {{class_name}}_{{method.name}}_ForwardToCallback
: public mojo::MessageReceiver {
public:
{{class_name}}_{{method.name}}_ForwardToCallback(
{{class_name}}::{{method.name}}Callback callback
) : callback_(std::move(callback)) {
}
bool Accept(mojo::Message* message) override;
private:
{{class_name}}::{{method.name}}Callback callback_;
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ForwardToCallback);
};
{%- endif %}
{%- endfor %}
{{proxy_name}}::{{proxy_name}}(mojo::MessageReceiverWithResponder* receiver)
: receiver_(receiver) {
}
{#--- Proxy definitions #}
{%- for method in interface.methods %}
{%- set message_name =
"internal::k%s_%s_Name"|format(interface.name, method.name) %}
{%- set params_struct = method.param_struct %}
{%- set params_description =
"%s.%s request"|format(interface.name, method.name) %}
{%- set message_typename = "%s_%s_Message"|format(proxy_name, method.name) %}
{%- if method|method_supports_lazy_serialization %}
{{interface_macros.define_message_type(
interface, message_typename, message_name, False, method, method.parameters,
params_struct, params_description)}}
{%- endif %}
{%- if method.sync %}
bool {{proxy_name}}::{{method.name}}(
{{interface_macros.declare_sync_method_params("param_", method)}}) {
#if BUILDFLAG(MOJO_TRACE_ENABLED)
TRACE_EVENT0("mojom", "{{namespace_as_string}}::{{class_name}}::{{method.name}}");
#endif
const bool kExpectsResponse = true;
const bool kIsSync = true;
{%- if method|method_supports_lazy_serialization %}
const bool kSerialize = receiver_->PrefersSerializedMessages();
auto message = {{message_typename}}::Build(
kSerialize, kExpectsResponse, kIsSync
{%- for param in method.parameters -%}
, std::move(param_{{param.name}})
{%- endfor %});
{%- else %}
{{interface_macros.build_message_flags(False, "kIsSync", "kExpectsResponse",
"kFlags")}}
{{interface_macros.build_serialized_message(
message_name, "param_%s", params_struct, params_description, "kFlags",
"message")}}
{%- endif %}
#if defined(ENABLE_IPC_FUZZER)
message.set_interface_name({{class_name}}::Name_);
message.set_method_name("{{method.name}}");
#endif
bool result = false;
std::unique_ptr<mojo::MessageReceiver> responder(
new {{class_name}}_{{method.name}}_HandleSyncResponse(
&result
{%- for param in method.response_parameters -%}
, out_param_{{param.name}}
{%- endfor %}));
ignore_result(receiver_->AcceptWithResponder(&message, std::move(responder)));
return result;
}
{%- endif %}
void {{proxy_name}}::{{method.name}}(
{{interface_macros.declare_request_params("in_", method)}}) {
#if BUILDFLAG(MOJO_TRACE_ENABLED)
TRACE_EVENT0("mojom", "{{namespace_as_string}}::{{class_name}}::{{method.name}}");
#endif
{%- if method.response_parameters != None %}
const bool kExpectsResponse = true;
{%- else %}
const bool kExpectsResponse = false;
{%- endif %}
const bool kIsSync = false;
{%- if method|method_supports_lazy_serialization %}
const bool kSerialize = receiver_->PrefersSerializedMessages();
auto message = {{message_typename}}::Build(
kSerialize, kExpectsResponse, kIsSync
{%- for param in method.parameters -%}
, std::move(in_{{param.name}})
{%- endfor %});
{%- else %}
{{interface_macros.build_message_flags(False, "kIsSync", "kExpectsResponse",
"kFlags")}}
{{interface_macros.build_serialized_message(
message_name, "in_%s", params_struct, params_description, "kFlags",
"message")}}
{%- endif %}
#if defined(ENABLE_IPC_FUZZER)
message.set_interface_name({{class_name}}::Name_);
message.set_method_name("{{method.name}}");
#endif
{%- if method.response_parameters != None %}
std::unique_ptr<mojo::MessageReceiver> responder(
new {{class_name}}_{{method.name}}_ForwardToCallback(
std::move(callback)));
ignore_result(receiver_->AcceptWithResponder(&message, std::move(responder)));
{%- else %}
// This return value may be ignored as false implies the Connector has
// encountered an error, which will be visible through other means.
ignore_result(receiver_->Accept(&message));
{%- endif %}
}
{%- endfor %}
{#--- ProxyToResponder definition #}
{%- for method in interface.methods -%}
{%- if method.response_parameters != None %}
{%- set message_name =
"internal::k%s_%s_Name"|format(interface.name, method.name) %}
{%- set response_params_struct = method.response_param_struct %}
{%- set params_description =
"%s.%s response"|format(interface.name, method.name) %}
{%- set response_message_typename =
"%s_%s_Response_Message"|format(interface.name, method.name) %}
class {{class_name}}_{{method.name}}_ProxyToResponder {
public:
static {{class_name}}::{{method.name}}Callback CreateCallback(
uint64_t request_id,
bool is_sync,
std::unique_ptr<mojo::MessageReceiverWithStatus> responder) {
std::unique_ptr<{{class_name}}_{{method.name}}_ProxyToResponder> proxy(
new {{class_name}}_{{method.name}}_ProxyToResponder(
request_id, is_sync, std::move(responder)));
return base::BindOnce(&{{class_name}}_{{method.name}}_ProxyToResponder::Run,
std::move(proxy));
}
~{{class_name}}_{{method.name}}_ProxyToResponder() {
#if DCHECK_IS_ON()
if (responder_) {
// If we're being destroyed without being run, we want to ensure the
// binding endpoint has been closed. This checks for that asynchronously.
// We pass a bound generated callback to handle the response so that any
// resulting DCHECK stack will have useful interface type information.
responder_->IsConnectedAsync(base::BindOnce(&OnIsConnectedComplete));
}
#endif
// If the Callback was dropped then deleting the responder will close
// the pipe so the calling application knows to stop waiting for a reply.
responder_ = nullptr;
}
private:
{{class_name}}_{{method.name}}_ProxyToResponder(
uint64_t request_id,
bool is_sync,
std::unique_ptr<mojo::MessageReceiverWithStatus> responder)
: request_id_(request_id),
is_sync_(is_sync),
responder_(std::move(responder)) {
}
#if DCHECK_IS_ON()
static void OnIsConnectedComplete(bool connected) {
DCHECK(!connected)
<< "{{class_name}}::{{method.name}}Callback was destroyed without "
<< "first either being run or its corresponding binding being closed. "
<< "It is an error to drop response callbacks which still correspond "
<< "to an open interface pipe.";
}
#endif
void Run(
{{interface_macros.declare_params("in_", method.response_parameters)}});
uint64_t request_id_;
bool is_sync_;
std::unique_ptr<mojo::MessageReceiverWithStatus> responder_;
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ProxyToResponder);
};
{%- if method|method_supports_lazy_serialization %}
{{interface_macros.define_message_type(
interface, response_message_typename, message_name, True, method,
method.response_parameters, response_params_struct, params_description)}}
{%- endif %}
bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
mojo::Message* message) {
#if BUILDFLAG(MOJO_TRACE_ENABLED)
TRACE_EVENT1("mojom", "{{namespace_as_string}}::{{class_name}}::{{method.name}}Callback",
"message", message->name());
#endif
mojo::internal::MessageDispatchContext dispatch_context(message);
{%- if method|method_supports_lazy_serialization %}
if (!message->is_serialized()) {
auto context =
message->TakeUnserializedContext<{{response_message_typename}}>();
if (!context) {
// The Message was not of the expected type. It may be a valid message
// which was build using a different variant of these bindings. Force
// serialization before dispatch in this case.
message->SerializeIfNecessary();
} else {
if (!callback_.is_null())
context->Dispatch(&callback_);
return true;
}
}
{%- endif %}
DCHECK(message->is_serialized());
internal::{{class_name}}_{{method.name}}_ResponseParams_Data* params =
reinterpret_cast<
internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
message->mutable_payload());
{%- set desc = class_name~"::"~method.name~" response" %}
{{alloc_params(method.response_param_struct, "params", "message", desc)}}
if (!callback_.is_null())
std::move(callback_).Run({{pass_params(method.response_parameters)}});
return true;
}
void {{class_name}}_{{method.name}}_ProxyToResponder::Run(
{{interface_macros.declare_params("in_", method.response_parameters)}}) {
{%- if method|method_supports_lazy_serialization %}
const bool kSerialize = responder_->PrefersSerializedMessages();
auto message = {{response_message_typename}}::Build(kSerialize, is_sync_
{%- for param in method.response_parameters -%}
, std::move(in_{{param.name}})
{%- endfor %});
{%- else %}
{{interface_macros.build_message_flags(True, "is_sync_", "false", "kFlags")}}
{{interface_macros.build_serialized_message(
message_name, "in_%s", response_params_struct,
response_params_description, "kFlags", "message")}}
{%- endif %}
#if BUILDFLAG(MOJO_TRACE_ENABLED)
TRACE_EVENT1("mojom", "(Impl){{namespace_as_string}}::{{class_name}}::{{method.name}}Callback",
"message", message.name());
#endif
#if defined(ENABLE_IPC_FUZZER)
message.set_interface_name({{class_name}}::Name_);
message.set_method_name("{{method.name}}");
#endif
message.set_request_id(request_id_);
ignore_result(responder_->Accept(&message));
// TODO(darin): Accept() returning false indicates a malformed message, and
// that may be good reason to close the connection. However, we don't have a
// way to do that from here. We should add a way.
responder_ = nullptr;
}
{%- endif -%}
{%- if method.sync %}
bool {{class_name}}_{{method.name}}_HandleSyncResponse::Accept(
mojo::Message* message) {
{%- if method|method_supports_lazy_serialization %}
if (!message->is_serialized()) {
auto context =
message->TakeUnserializedContext<{{response_message_typename}}>();
if (!context) {
// The Message was not of the expected type. It may be a valid message
// which was built using a different variant of these bindings. Force
// serialization before dispatch in this case.
message->SerializeIfNecessary();
} else {
context->HandleSyncResponse(
{%- for param in method.response_parameters %}
out_{{param.name}}_
{%- if not loop.last -%}, {% endif -%}
{%- endfor %});
*result_ = true;
mojo::internal::SyncMessageResponseSetup::SetCurrentSyncResponseMessage(
message);
return true;
}
}
{%- endif %}
DCHECK(message->is_serialized());
internal::{{class_name}}_{{method.name}}_ResponseParams_Data* params =
reinterpret_cast<internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
message->mutable_payload());
{%- set desc = class_name~"::"~method.name~" response" %}
{{alloc_params(method.response_param_struct, "params", "message", desc)}}
{%- for param in method.response_parameters %}
*out_{{param.name}}_ = std::move(p_{{param.name}});
{%- endfor %}
mojo::internal::SyncMessageResponseSetup::SetCurrentSyncResponseMessage(
message);
*result_ = true;
return true;
}
{%- endif %}
{%- endfor %}
{#--- StubDispatch definition #}
// static
bool {{class_name}}StubDispatch::Accept(
{{interface.name}}* impl,
mojo::Message* message) {
{%- if interface.methods %}
switch (message->header()->name) {
{%- for method in interface.methods %}
case internal::k{{class_name}}_{{method.name}}_Name: {
#if BUILDFLAG(MOJO_TRACE_ENABLED)
TRACE_EVENT1("mojom", "(Impl){{namespace_as_string}}::{{class_name}}::{{method.name}}",
"message", message->name());
#endif
{%- if method.response_parameters == None %}
mojo::internal::MessageDispatchContext context(message);
{%- if method|method_supports_lazy_serialization %}
if (!message->is_serialized()) {
auto context = message->TakeUnserializedContext<
{{proxy_name}}_{{method.name}}_Message>();
if (!context) {
// The Message was not of the expected type. It may be a valid message
// which was serialized using a different variant of these bindings.
// Force serialization before dispatch in this case.
message->SerializeIfNecessary();
} else {
context->Dispatch(impl);
return true;
}
}
{%- endif %}
DCHECK(message->is_serialized());
internal::{{class_name}}_{{method.name}}_Params_Data* params =
reinterpret_cast<internal::{{class_name}}_{{method.name}}_Params_Data*>(
message->mutable_payload());
{%- set desc = class_name~"::"~method.name %}
{{alloc_params(method.param_struct, "params", "message", desc)|
indent(4)}}
// A null |impl| means no implementation was bound.
assert(impl);
impl->{{method.name}}({{pass_params(method.parameters)}});
return true;
{%- else %}
break;
{%- endif %}
}
{%- endfor %}
}
{%- endif %}
return false;
}
// static
bool {{class_name}}StubDispatch::AcceptWithResponder(
{{interface.name}}* impl,
mojo::Message* message,
std::unique_ptr<mojo::MessageReceiverWithStatus> responder) {
{%- if interface.methods %}
switch (message->header()->name) {
{%- for method in interface.methods %}
case internal::k{{class_name}}_{{method.name}}_Name: {
#if BUILDFLAG(MOJO_TRACE_ENABLED)
TRACE_EVENT1("mojom", "(Impl){{namespace_as_string}}::{{class_name}}::{{method.name}}",
"message", message->name());
#endif
{%- if method.response_parameters != None %}
mojo::internal::MessageDispatchContext context(message);
{%- if method|method_supports_lazy_serialization %}
if (!message->is_serialized()) {
auto context = message->TakeUnserializedContext<
{{proxy_name}}_{{method.name}}_Message>();
if (!context) {
// The Message was not of the expected type. It may be a valid message
// which was built using a different variant of these bindings. Force
// serialization before dispatch in this case.
message->SerializeIfNecessary();
} else {
{{class_name}}::{{method.name}}Callback callback =
{{class_name}}_{{method.name}}_ProxyToResponder::CreateCallback(
message->request_id(),
message->has_flag(mojo::Message::kFlagIsSync),
std::move(responder));
context->Dispatch(impl, std::move(callback));
return true;
}
}
{%- endif %}
internal::{{class_name}}_{{method.name}}_Params_Data* params =
reinterpret_cast<
internal::{{class_name}}_{{method.name}}_Params_Data*>(
message->mutable_payload());
{%- set desc = class_name~"::"~method.name %}
{{alloc_params(method.param_struct, "params", "message", desc)|
indent(4)}}
{{class_name}}::{{method.name}}Callback callback =
{{class_name}}_{{method.name}}_ProxyToResponder::CreateCallback(
message->request_id(),
message->has_flag(mojo::Message::kFlagIsSync),
std::move(responder));
// A null |impl| means no implementation was bound.
assert(impl);
impl->{{method.name}}(
{%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}std::move(callback));
return true;
{%- else %}
break;
{%- endif %}
}
{%- endfor %}
}
{%- endif %}
return false;
}
{#--- Request validator definitions #}
bool {{class_name}}RequestValidator::Accept(mojo::Message* message) {
if (!message->is_serialized() ||
mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
return true;
}
mojo::internal::ValidationContext validation_context(
message->payload(), message->payload_num_bytes(),
message->handles()->size(), message->payload_num_interface_ids(), message,
"{{class_name}} RequestValidator");
switch (message->header()->name) {
{%- for method in interface.methods %}
case internal::k{{class_name}}_{{method.name}}_Name: {
{%- if method.response_parameters != None %}
if (!mojo::internal::ValidateMessageIsRequestExpectingResponse(
message, &validation_context)) {
return false;
}
{%- else %}
if (!mojo::internal::ValidateMessageIsRequestWithoutResponse(
message, &validation_context)) {
return false;
}
{%- endif %}
if (!mojo::internal::ValidateMessagePayload<
internal::{{class_name}}_{{method.name}}_Params_Data>(
message, &validation_context)) {
return false;
}
return true;
}
{%- endfor %}
default:
break;
}
// Unrecognized message.
ReportValidationError(
&validation_context,
mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD);
return false;
}
{#--- Response validator definitions #}
{% if interface|has_callbacks %}
bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) {
if (!message->is_serialized() ||
mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
return true;
}
mojo::internal::ValidationContext validation_context(
message->payload(), message->payload_num_bytes(),
message->handles()->size(), message->payload_num_interface_ids(), message,
"{{class_name}} ResponseValidator");
if (!mojo::internal::ValidateMessageIsResponse(message, &validation_context))
return false;
switch (message->header()->name) {
{%- for method in interface.methods if method.response_parameters != None %}
case internal::k{{class_name}}_{{method.name}}_Name: {
if (!mojo::internal::ValidateMessagePayload<
internal::{{class_name}}_{{method.name}}_ResponseParams_Data>(
message, &validation_context)) {
return false;
}
return true;
}
{%- endfor %}
default:
break;
}
// Unrecognized message.
ReportValidationError(
&validation_context,
mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD);
return false;
}
{%- endif -%}
{#--- Testing interceptor #}
{%- for method in interface.methods %}
void {{interface.name}}InterceptorForTesting::{{method.name}}({{interface_macros.declare_request_params("", method)}}) {
GetForwardingInterface()->{{method.name}}(
{%- for param in method.parameters -%}
std::move({{param.name}}){%- if not loop.last %}, {% endif %}
{%- endfor %}
{%- if method.response_parameters != None -%}
{%- if method.parameters %}, {% endif -%}
std::move(callback)
{%- endif -%}
);
}
{%- endfor %}
{#--- Async wait helper for testing #}
{{interface.name}}AsyncWaiter::{{interface.name}}AsyncWaiter(
{{interface.name}}* proxy) : proxy_(proxy) {}
{{interface.name}}AsyncWaiter::~{{interface.name}}AsyncWaiter() = default;
{% for method in interface.methods if method.response_parameters != None -%}
void {{interface.name}}AsyncWaiter::{{method.name}}(
{{interface_macros.declare_sync_method_params("", method)}}) {
base::RunLoop loop;
proxy_->{{method.name}}(
{%- for param in method.parameters -%}
std::move({{param.name}}),
{%- endfor %}
base::BindOnce(
[](base::RunLoop* loop
{%- for param in method.response_parameters -%},
{{param.kind|cpp_wrapper_call_type}}* out_{{param.name}}
{% endfor -%}
{%- for param in method.response_parameters -%},
{{param.kind|cpp_wrapper_param_type}} {{param.name}}
{%- endfor %}) {
{%- for param in method.response_parameters -%}
*out_{{param.name}} = std::move({{param.name}});
{%- endfor %}
loop->Quit();
},
&loop
{%- for param in method.response_parameters -%},
out_{{param.name}}
{%- endfor %}));
loop.Run();
}
{% endfor %}