{%- 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}}"; {%- if interface.uuid %} constexpr base::Token {{class_name}}::Uuid_; {%- endif %} {#--- 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( {%- if use_once_callback %} {{class_name}}::{{method.name}}Callback callback {%- else %} const {{class_name}}::{{method.name}}Callback& callback {%- endif %} ) : 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, use_once_callback)}} {%- 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 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, use_once_callback)}}) { #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 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 responder) { std::unique_ptr<{{class_name}}_{{method.name}}_ProxyToResponder> proxy( new {{class_name}}_{{method.name}}_ProxyToResponder( request_id, is_sync, std::move(responder))); {%- if use_once_callback %} return base::BindOnce(&{{class_name}}_{{method.name}}_ProxyToResponder::Run, std::move(proxy)); {%- else %} return base::Bind(&{{class_name}}_{{method.name}}_ProxyToResponder::Run, base::Passed(&proxy)); {%- endif %} } ~{{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 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 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, use_once_callback)}} {%- 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( 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( 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 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, use_once_callback)}}) { 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 %} {%- if use_once_callback %} base::BindOnce( {%- else %} base::Bind( {%- endif %} [](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 %}