1// Copyright 2019 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "{{module.path}}-mojolpm.h" 6 7#include <functional> 8 9#include "base/no_destructor.h" 10#include "base/task/post_task.h" 11 12{% for extra_traits_header in all_extra_traits_headers %} 13#include "{{extra_traits_header}}" 14{%- endfor %} 15 16{%- import "mojolpm_macros.tmpl" as util %} 17{%- import "mojolpm_from_proto_macros.tmpl" as from_proto %} 18{%- import "mojolpm_to_proto_macros.tmpl" as to_proto %} 19{%- import "mojolpm_traits_specialization_macros.tmpl" as traits_specialization %} 20 21namespace mojo { 22{%- for struct in structs %} 23{{- traits_specialization.define_struct(struct) }} 24{%- endfor %} 25 26{%- for union in unions %} 27{{ traits_specialization.define_union(union) }} 28{%- endfor %} 29} // namespace mojo 30 31namespace mojolpm { 32{%- for enum in all_enums %} 33{{- from_proto.define_enum(enum) }} 34{{- to_proto.define_enum(enum) }} 35{%- endfor %} 36 37{%- for struct in structs %} 38{%- set proto_type = "::mojolpm" ~ (struct|get_qualified_name_for_kind(flatten_nested_kind=True)) %} 39{%- set struct_type = proto_type ~ "_ProtoStruct" %} 40{%- for field in struct.fields %} 41{%- set name = field.name|camel_to_under %} 42{%- set kind = field.kind %} 43{%- if kind|is_array_kind or kind|is_map_kind %} 44{{- from_proto.define(struct_type, kind, name) }} 45{{- to_proto.define(struct_type, kind, name) }} 46{%- endif %} 47{%- endfor %} 48{{- from_proto.define_struct(struct) }} 49{{- to_proto.define_struct(struct) }} 50{%- endfor %} 51 52{%- for union in unions %} 53{%- set proto_type = "::mojolpm" ~ (union|get_qualified_name_for_kind(flatten_nested_kind=True)) %} 54{%- set union_type = proto_type ~ "_ProtoUnion" %} 55{%- for field in union.fields %} 56{%- set name = field.name|camel_to_under %} 57{%- set kind = field.kind %} 58{%- if kind|is_array_kind or kind|is_map_kind %} 59{{- from_proto.define(union_type, kind, name)}} 60{{- to_proto.define(union_type, kind, name)}} 61{%- endif %} 62{%- endfor %} 63{{- from_proto.define_union(union) }} 64{{- to_proto.define_union(union) }} 65{%- endfor %} 66 67{%- for interface in interfaces %} 68{%- set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %} 69{%- set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %} 70class {{interface.name}}Impl : public {{mojom_type}} { 71 public: 72 {{interface.name}}Impl() { 73 } 74 75{%- for method in interface.methods -%}{{"\n"}} 76 void {{method.name}}({{ "\n" }} 77{%- for param in method.parameters -%} 78{%- set name = param.name|camel_to_under -%} 79{%- set kind = param.kind -%} 80{%- set param_mojom_type = kind|cpp_wrapper_param_type(add_same_module_namespaces=true) -%} 81{{ ",\n" if not loop.first }} {{param_mojom_type}} {{name}} 82{%- endfor -%} 83{%- if method.response_parameters != None -%} 84{{ ",\n" if method.parameters }} {{mojom_type}}::{{method.name}}Callback callback 85{%- endif -%} 86) override { 87{%- for param in method.parameters -%} 88{%- set name = param.name|camel_to_under -%} 89{%- set kind = param.kind -%} 90{{ util.add_instance(kind, name, False)|indent(2, True) }} 91{%- endfor %} 92 mojolpmdbg("{{interface.name}}Impl.{{method.name}}\n"); 93{%- if method.response_parameters != None %} 94 mojolpm::GetContext()->AddInstance<{{mojom_type}}::{{method.name}}Callback>(std::move(callback)); 95{%- endif %} 96 } 97{%- endfor %} 98}; 99 100bool FromProto(uint32_t input, 101 ::mojo::PendingRemote<{{mojom_type}}>& output) { 102 bool result = false; 103 ::mojo::Remote<{{mojom_type}}>* output_ptr = nullptr; 104 105 if (input) { 106 output_ptr = mojolpm::GetContext()->GetInstance<::mojo::Remote<{{mojom_type}}>>(input); 107 if (output_ptr) { 108 // TODO(markbrand): look for a cleaner way to handle this check. 109 if (!output_ptr->is_bound() || (output_ptr->internal_state() 110 && output_ptr->internal_state()->has_pending_callbacks())) { 111 // not safe to Unbind, so fail instead. 112 output_ptr = nullptr; 113 } else { 114 output = output_ptr->Unbind(); 115 result = true; 116 } 117 } 118 } else { 119 auto impl = std::make_unique<{{interface.name}}Impl>(); 120 auto receiver_ptr = 121 std::make_unique<::mojo::Receiver<{{mojom_type}}>>( 122 impl.get(), output.InitWithNewPipeAndPassReceiver()); 123 mojolpm::GetContext()->AddInstance(std::move(impl)); 124 mojolpm::GetContext()->AddInstance(std::move(receiver_ptr)); 125 result = true; 126 } 127 128 return result; 129} 130 131bool ToProto(::mojo::PendingRemote<{{mojom_type}}>&& input, 132 uint32_t& output) { 133 ::mojo::Remote<{{mojom_type}}> remote(std::move(input)); 134 int next_id = NextId<{{mojom_type}}>(); 135 output = mojolpm::GetContext()->AddInstance(next_id, std::move(remote)); 136 return true; 137} 138 139bool FromProto(uint32_t input, 140 ::mojo::PendingReceiver<{{mojom_type}}>& output) { 141 ::mojo::Remote<{{mojom_type}}> remote = ::mojo::Remote<{{mojom_type}}>(); 142 output = remote.BindNewPipeAndPassReceiver(); 143 mojolpm::GetContext()->AddInstance(input, std::move(remote)); 144 return true; 145} 146 147bool ToProto(::mojo::PendingReceiver<{{mojom_type}}>&& input, 148 uint32_t& output) { 149 // This should only get called from callbacks into the fuzzer, ie from one of 150 // the XxxImpls or from a return callback. Since that is the case, we want to 151 // bind the receiver and store it. 152 153 auto impl = std::make_unique<{{interface.name}}Impl>(); 154 auto receiver_ptr = std::make_unique<::mojo::Receiver<{{mojom_type}}>>( 155 impl.get(), std::move(input)); 156 mojolpm::GetContext()->AddInstance(std::move(impl)); 157 output = mojolpm::GetContext()->AddInstance(std::move(receiver_ptr)); 158 return true; 159} 160 161bool FromProto(uint32_t input, 162 ::mojo::PendingAssociatedRemote<{{mojom_type}}>& output) { 163 mojolpmdbg("PendingAssociatedRemote {{interface.name}}\n"); 164 bool result = false; 165 ::mojo::AssociatedRemote<{{mojom_type}}>* output_ptr; 166 167 if (input) { 168 output_ptr = mojolpm::GetContext()->GetInstance<::mojo::AssociatedRemote<{{mojom_type}}>>(input); 169 if (output_ptr) { 170 // TODO(markbrand): look for a cleaner way to handle this check. 171 if (!output_ptr->is_bound() || (output_ptr->internal_state() 172 && output_ptr->internal_state()->has_pending_callbacks())) { 173 // not safe to Unbind, so fail instead. 174 output_ptr = nullptr; 175 } else { 176 output = output_ptr->Unbind(); 177 result = true; 178 } 179 } 180 } else { 181 auto impl = std::make_unique<{{interface.name}}Impl>(); 182 auto receiver_ptr = 183 std::make_unique<::mojo::AssociatedReceiver<{{mojom_type}}>>( 184 impl.get(), output.InitWithNewEndpointAndPassReceiver()); 185 mojolpm::GetContext()->AddInstance(std::move(impl)); 186 mojolpm::GetContext()->AddInstance(std::move(receiver_ptr)); 187 result = true; 188 } 189 190 return result; 191} 192 193bool ToProto(::mojo::PendingAssociatedRemote<{{mojom_type}}>&& input, 194 uint32_t& output) { 195 ::mojo::AssociatedRemote<{{mojom_type}}> remote(std::move(input)); 196 int next_id = NextId<{{mojom_type}}>(); 197 output = mojolpm::GetContext()->AddInstance(next_id, std::move(remote)); 198 return true; 199} 200 201bool FromProto(uint32_t input, 202 ::mojo::PendingAssociatedReceiver<{{mojom_type}}>& output) { 203 ::mojo::AssociatedRemote<{{mojom_type}}> remote = ::mojo::AssociatedRemote<{{mojom_type}}>(); 204 output = remote.BindNewEndpointAndPassReceiver(); 205 mojolpm::GetContext()->AddInstance(input, std::move(remote)); 206 return true; 207} 208 209bool ToProto(::mojo::PendingAssociatedReceiver<{{mojom_type}}>&& input, 210 uint32_t& output) { 211 // This should only get called from callbacks into the fuzzer, ie from one of 212 // the XxxImpls or from a return callback. Since that is the case, we want to 213 // bind the receiver and store it. 214 215 auto impl = std::make_unique<{{interface.name}}Impl>(); 216 auto receiver_ptr = std::make_unique<::mojo::AssociatedReceiver<{{mojom_type}}>>( 217 impl.get(), std::move(input)); 218 mojolpm::GetContext()->AddInstance(std::move(impl)); 219 output = mojolpm::GetContext()->AddInstance(std::move(receiver_ptr)); 220 return true; 221}{{"\n"-}} 222 223{%- for method in interface.methods %} 224{%- set method_type = proto_type ~ "::" ~ interface.name ~ "_" ~ method.name %} 225{%- for param in method.parameters %} 226{%- set name = param.name|camel_to_under %} 227{%- set kind = param.kind %} 228{%- if kind|is_array_kind or kind|is_map_kind -%} 229{{ from_proto.define(method_type, kind, name) }} 230{{ to_proto.define(method_type, kind, name) }} 231{%- endif %} 232{%- endfor %} 233{%- endfor %} 234{%- for method in interface.methods %} 235{%- if method.response_parameters != None %} 236{%- set method_type = proto_type ~ "::" ~ interface.name ~ "_" ~ method.name ~ "Response" %} 237{%- for param in method.response_parameters %} 238{%- set name = param.name %} 239{%- set kind = param.kind %} 240{%- if kind|is_array_kind or kind|is_map_kind -%} 241{{- from_proto.define(method_type, kind, name)}} 242{{- to_proto.define(method_type, kind, name)}} 243{%- endif %} 244{%- endfor %} 245{%- endif %} 246{%- endfor %} 247{%- endfor %} 248 249{%- for interface in interfaces %} 250{%- set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %} 251{%- set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %} 252{%- if interface.methods %} 253bool HandleRemoteAction(const {{proto_type}}::RemoteAction& input) { 254 bool result = true; 255 256 switch (input.method_case()) { 257{%- for method in interface.methods %} 258 case {{proto_type}}::RemoteAction::k{{("m_" ~ method.name)|under_to_camel(digits_split=True)}}: { 259 result = HandleRemoteCall(input.id(), input.{{("m" ~ method.name)|camel_to_under}}()); 260 } break; 261{%- endfor %} 262 case {{proto_type}}::RemoteAction::kReset: { 263 mojolpm::GetContext()->GetAndRemoveInstance<::mojo::Remote<{{mojom_type}}>>(input.id()); 264 } break; 265 266 default: { 267 result = false; 268 } 269 } 270 271 return result; 272} 273 274bool HandleAssociatedRemoteAction(const {{proto_type}}::AssociatedRemoteAction& input) { 275 bool result = true; 276 277 switch (input.method_case()) { 278{%- for method in interface.methods %} 279 case {{proto_type}}::AssociatedRemoteAction::k{{("m_" ~ method.name)|under_to_camel(digits_split=True)}}: { 280 result = HandleAssociatedRemoteCall(input.id(), input.{{("m" ~ method.name)|camel_to_under}}()); 281 } break; 282{%- endfor %} 283 case {{proto_type}}::AssociatedRemoteAction::kReset: { 284 mojolpm::GetContext()->GetAndRemoveInstance<::mojo::AssociatedRemote<{{mojom_type}}>>(input.id()); 285 } break; 286 287 default: { 288 result = false; 289 } 290 } 291 292 return result; 293} 294 295bool HandleReceiverAction( 296 const {{proto_type}}::ReceiverAction& input) { 297 bool result = true; 298 switch (input.response_case()) { 299{%- for method in interface.methods %} 300 case {{proto_type}}::ReceiverAction::k{{("m_" ~ method.name ~ "_response")|under_to_camel(digits_split=True)}}: { 301 result = HandleResponse(input.id(), input.{{("m" ~ method.name ~ "_response")|camel_to_under}}()); 302 } break; 303{%- endfor %} 304 305 default: { 306 result = false; 307 } 308 } 309 310 return result; 311}{{"\n"-}} 312{%- for method in interface.methods %} 313{%- if method.response_parameters != None %} 314static void {{interface.name}}_{{method.name}}Callback( 315{%- for param in method.response_parameters %} 316{%- set name = param.name|camel_to_under %} 317{%- set kind = param.kind %} 318{%- set param_mojom_type = kind|cpp_wrapper_param_type(add_same_module_namespaces=true) %}{{ ',' if not loop.first }} 319 {{param_mojom_type}} param_{{name}} 320{%- endfor -%} 321) { 322{%- for param in method.response_parameters %} 323{%- set name = param.name|camel_to_under %} 324{%- set kind = param.kind %} 325{{ util.add_instance(kind, 'param_' ~ name, False) }} 326{%- endfor %} 327 mojolpmdbg("{{interface.name}}.{{method.name}}Callback\n"); 328}{{"\n"-}} 329{%- endif %} 330template <typename T> 331bool HandleCall(uint32_t instance_id, 332 const {{proto_type}}::{{interface.name}}_{{method.name}}& input) { 333 T* instance = 334 mojolpm::GetContext()->GetInstance<T>(instance_id); 335 if (!instance || !instance->is_bound() || !instance->is_connected()) { 336 return false; 337 } 338 339 mojolpm::GetContext()->StartDeserialization(); 340 341 bool mojolpm_result = true; 342{%- for param in method.parameters %} 343{%- set name = param.name|camel_to_under %} 344{%- set kind = param.kind %} 345{%- set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %} 346{%- set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %} 347 {{param_mojom_type}} local_{{name}}; 348{%- if kind|is_nullable_kind %} 349 {{param_maybe_mojom_type}} local_maybe_{{name}}; 350{%- endif %} 351{%- endfor %} 352 353{%- for param in method.parameters -%} 354{%- set name = param.name|camel_to_under %} 355{%- set kind = param.kind %} 356{%- if not kind|is_nullable_kind %} 357 mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}}); 358{%- else %} 359 if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) { 360 local_{{name}} = std::move(local_maybe_{{name}}); 361 } 362{%- endif %} 363{%- endfor %} 364 if (mojolpm_result) { 365 (*instance)->{{method.name}}( 366{%- for param in method.parameters -%} 367{%- set name = param.name|camel_to_under %} 368{%- set kind = param.kind %} 369 std::move(local_{{name}}){{ ',' if not loop.last }} 370{%- endfor -%} 371{%- if method.response_parameters != None -%} 372{{ ',' if method.parameters }} 373 base::BindOnce(&{{interface.name}}_{{method.name}}Callback)); 374{%- else -%} 375); 376{%- endif -%} 377 mojolpm::GetContext()->EndDeserialization(Context::Rollback::kNoRollback); 378 } else { 379 mojolpm::GetContext()->EndDeserialization(Context::Rollback::kRollback); 380 mojolpmdbg("call failed\n"); 381 } 382 383 return mojolpm_result; 384} 385 386bool HandleRemoteCall( 387 uint32_t instance_id, const {{proto_type}}::{{interface.name}}_{{method.name}}& input) { 388 mojolpmdbg("HandleRemoteCall({{interface.name}}::{{method.name}})\n"); 389 return HandleCall<::mojo::Remote<{{mojom_type}}>>(instance_id, input); 390} 391 392bool HandleAssociatedRemoteCall( 393 uint32_t instance_id, const {{proto_type}}::{{interface.name}}_{{method.name}}& input) { 394 mojolpmdbg("HandleAssociatedRemoteCall({{interface.name}}::{{method.name}})\n"); 395 return HandleCall<::mojo::AssociatedRemote<{{mojom_type}}>>(instance_id, input); 396} 397 398bool HandleResponse( 399 uint32_t callback_id, const {{proto_type}}::{{interface.name}}_{{method.name}}Response& input) { 400 mojolpmdbg("HandleResponse({{interface.name}}::{{method.name}})\n"); 401{%- if method.response_parameters == None %} 402 return true; 403{%- else %} 404 auto mojolpm_callback = mojolpm::GetContext()->GetAndRemoveInstance< 405 {{mojom_type}}::{{method.name}}Callback>(callback_id); 406 407 if (!mojolpm_callback) { 408 return true; 409 } 410 411 mojolpm::GetContext()->StartDeserialization(); 412 413 bool mojolpm_result = true; 414{%- for param in method.response_parameters %} 415{%- set name = param.name|camel_to_under %} 416{%- set kind = param.kind %} 417{%- set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %} 418{%- set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %} 419 {{param_mojom_type}} local_{{name}}; 420{%- if kind|is_nullable_kind %} 421 {{param_maybe_mojom_type}} local_maybe_{{name}}; 422{%- endif %} 423{%- endfor %} 424 425{%- for param in method.response_parameters -%} 426{%- set name = param.name|camel_to_under %} 427{%- set kind = param.kind %} 428{%- if not kind|is_nullable_kind %} 429 mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}}); 430 mojolpmdbg("{{name}} %i\n", mojolpm_result); 431{%- else %} 432 if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) { 433 local_{{name}} = std::move(local_maybe_{{name}}); 434 } 435{%- endif %} 436{%- endfor %} 437 if (mojolpm_result) { 438 std::move(*mojolpm_callback).Run( 439{%- for param in method.response_parameters -%} 440{%- set name = param.name|camel_to_under %} 441{%- set kind = param.kind %} 442{%- if kind|is_interface_kind or kind|is_associated_kind %} 443 {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }} 444{%- else %} 445 std::move(local_{{name}}){{ ',' if not loop.last }} 446{%- endif %} 447{%- endfor -%} 448); 449 mojolpm::GetContext()->EndDeserialization(Context::Rollback::kNoRollback); 450 } else { 451 mojolpm::GetContext()->EndDeserialization(Context::Rollback::kRollback); 452 mojolpm::GetContext()->AddInstance< 453 {{mojom_type}}::{{method.name}}Callback>(callback_id, std::move(*mojolpm_callback)); 454 } 455 456 return mojolpm_result; 457{%- endif %} 458}{{"\n"-}} 459{%- endfor %} 460{%- endif %} 461{%- endfor -%} 462} // namespace mojolpm 463