1 // Copyright (c) 2012 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 "ppapi/proxy/plugin_resource.h" 6 7 #include <limits> 8 9 #include "ppapi/proxy/plugin_globals.h" 10 #include "ppapi/proxy/ppapi_messages.h" 11 #include "ppapi/shared_impl/ppapi_globals.h" 12 13 namespace ppapi { 14 namespace proxy { 15 16 PluginResource::PluginResource(Connection connection, PP_Instance instance) 17 : Resource(OBJECT_IS_PROXY, instance), 18 connection_(connection), 19 next_sequence_number_(1), 20 sent_create_to_browser_(false), 21 sent_create_to_renderer_(false), 22 resource_reply_thread_registrar_( 23 PpapiGlobals::Get()->IsPluginGlobals() ? 24 PluginGlobals::Get()->resource_reply_thread_registrar() : NULL) { 25 } 26 27 PluginResource::~PluginResource() { 28 if (sent_create_to_browser_) { 29 connection_.browser_sender->Send( 30 new PpapiHostMsg_ResourceDestroyed(pp_resource())); 31 } 32 if (sent_create_to_renderer_) { 33 connection_.renderer_sender->Send( 34 new PpapiHostMsg_ResourceDestroyed(pp_resource())); 35 } 36 37 if (resource_reply_thread_registrar_) 38 resource_reply_thread_registrar_->Unregister(pp_resource()); 39 } 40 41 void PluginResource::OnReplyReceived( 42 const proxy::ResourceMessageReplyParams& params, 43 const IPC::Message& msg) { 44 TRACE_EVENT2("ppapi proxy", "PluginResource::OnReplyReceived", 45 "Class", IPC_MESSAGE_ID_CLASS(msg.type()), 46 "Line", IPC_MESSAGE_ID_LINE(msg.type())); 47 // Grab the callback for the reply sequence number and run it with |msg|. 48 CallbackMap::iterator it = callbacks_.find(params.sequence()); 49 if (it == callbacks_.end()) { 50 DCHECK(false) << "Callback does not exist for an expected sequence number."; 51 } else { 52 scoped_refptr<PluginResourceCallbackBase> callback = it->second; 53 callbacks_.erase(it); 54 callback->Run(params, msg); 55 } 56 } 57 58 void PluginResource::NotifyLastPluginRefWasDeleted() { 59 Resource::NotifyLastPluginRefWasDeleted(); 60 61 // The callbacks may hold referrences to this object. Normally, we will get 62 // reply messages from the host side and remove them. However, it is possible 63 // that some replies from the host never arrive, e.g., the corresponding 64 // renderer crashes. In that case, we have to clean up the callbacks, 65 // otherwise this object will live forever. 66 callbacks_.clear(); 67 } 68 69 void PluginResource::NotifyInstanceWasDeleted() { 70 Resource::NotifyInstanceWasDeleted(); 71 72 // Please see comments in NotifyLastPluginRefWasDeleted() about why we must 73 // clean up the callbacks. 74 // It is possible that NotifyLastPluginRefWasDeleted() is never called for a 75 // resource. For example, those singleton-style resources such as 76 // GamepadResource never expose references to the plugin and thus won't 77 // receive a NotifyLastPluginRefWasDeleted() call. For those resources, we 78 // need to clean up callbacks when the instance goes away. 79 callbacks_.clear(); 80 } 81 82 void PluginResource::SendCreate(Destination dest, const IPC::Message& msg) { 83 TRACE_EVENT2("ppapi proxy", "PluginResource::SendCreate", 84 "Class", IPC_MESSAGE_ID_CLASS(msg.type()), 85 "Line", IPC_MESSAGE_ID_LINE(msg.type())); 86 if (dest == RENDERER) { 87 DCHECK(!sent_create_to_renderer_); 88 sent_create_to_renderer_ = true; 89 } else { 90 DCHECK(!sent_create_to_browser_); 91 sent_create_to_browser_ = true; 92 } 93 ResourceMessageCallParams params(pp_resource(), GetNextSequence()); 94 GetSender(dest)->Send( 95 new PpapiHostMsg_ResourceCreated(params, pp_instance(), msg)); 96 } 97 98 void PluginResource::AttachToPendingHost(Destination dest, 99 int pending_host_id) { 100 // Connecting to a pending host is a replacement for "create". 101 if (dest == RENDERER) { 102 DCHECK(!sent_create_to_renderer_); 103 sent_create_to_renderer_ = true; 104 } else { 105 DCHECK(!sent_create_to_browser_); 106 sent_create_to_browser_ = true; 107 } 108 GetSender(dest)->Send( 109 new PpapiHostMsg_AttachToPendingHost(pp_resource(), pending_host_id)); 110 } 111 112 void PluginResource::Post(Destination dest, const IPC::Message& msg) { 113 TRACE_EVENT2("ppapi proxy", "PluginResource::Post", 114 "Class", IPC_MESSAGE_ID_CLASS(msg.type()), 115 "Line", IPC_MESSAGE_ID_LINE(msg.type())); 116 ResourceMessageCallParams params(pp_resource(), GetNextSequence()); 117 SendResourceCall(dest, params, msg); 118 } 119 120 bool PluginResource::SendResourceCall( 121 Destination dest, 122 const ResourceMessageCallParams& call_params, 123 const IPC::Message& nested_msg) { 124 // For in-process plugins, we need to send the routing ID with the request. 125 // The browser then uses that routing ID when sending the reply so it will be 126 // routed back to the correct RenderFrameImpl. 127 if (dest == BROWSER && connection_.in_process) { 128 return GetSender(dest)->Send(new PpapiHostMsg_InProcessResourceCall( 129 connection_.browser_sender_routing_id, 130 call_params, 131 nested_msg)); 132 } else { 133 return GetSender(dest)->Send( 134 new PpapiHostMsg_ResourceCall(call_params, nested_msg)); 135 } 136 } 137 138 int32_t PluginResource::GenericSyncCall( 139 Destination dest, 140 const IPC::Message& msg, 141 IPC::Message* reply, 142 ResourceMessageReplyParams* reply_params) { 143 TRACE_EVENT2("ppapi proxy", "PluginResource::GenericSyncCall", 144 "Class", IPC_MESSAGE_ID_CLASS(msg.type()), 145 "Line", IPC_MESSAGE_ID_LINE(msg.type())); 146 ResourceMessageCallParams params(pp_resource(), GetNextSequence()); 147 params.set_has_callback(); 148 bool success = GetSender(dest)->Send(new PpapiHostMsg_ResourceSyncCall( 149 params, msg, reply_params, reply)); 150 if (success) 151 return reply_params->result(); 152 return PP_ERROR_FAILED; 153 } 154 155 int32_t PluginResource::GetNextSequence() { 156 // Return the value with wraparound, making sure we don't make a sequence 157 // number with a 0 ID. Note that signed wraparound is undefined in C++ so we 158 // manually check. 159 int32_t ret = next_sequence_number_; 160 if (next_sequence_number_ == std::numeric_limits<int32_t>::max()) 161 next_sequence_number_ = 1; // Skip 0 which is invalid. 162 else 163 next_sequence_number_++; 164 return ret; 165 } 166 167 } // namespace proxy 168 } // namespace ppapi 169