plugin_resource.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/ppapi_messages.h" 10 11namespace ppapi { 12namespace proxy { 13 14PluginResource::PluginResource(Connection connection, PP_Instance instance) 15 : Resource(OBJECT_IS_PROXY, instance), 16 connection_(connection), 17 next_sequence_number_(1), 18 sent_create_to_browser_(false), 19 sent_create_to_renderer_(false) { 20} 21 22PluginResource::~PluginResource() { 23 if (sent_create_to_browser_) { 24 connection_.browser_sender->Send( 25 new PpapiHostMsg_ResourceDestroyed(pp_resource())); 26 } 27 if (sent_create_to_renderer_) { 28 connection_.renderer_sender->Send( 29 new PpapiHostMsg_ResourceDestroyed(pp_resource())); 30 } 31} 32 33void PluginResource::OnReplyReceived( 34 const proxy::ResourceMessageReplyParams& params, 35 const IPC::Message& msg) { 36 // Grab the callback for the reply sequence number and run it with |msg|. 37 CallbackMap::iterator it = callbacks_.find(params.sequence()); 38 if (it == callbacks_.end()) { 39 DCHECK(false) << "Callback does not exist for an expected sequence number."; 40 } else { 41 scoped_refptr<PluginResourceCallbackBase> callback = it->second; 42 callbacks_.erase(it); 43 callback->Run(params, msg); 44 } 45} 46 47void PluginResource::NotifyLastPluginRefWasDeleted() { 48 Resource::NotifyLastPluginRefWasDeleted(); 49 50 // The callbacks may hold referrences to this object. Normally, we will get 51 // reply messages from the host side and remove them. However, it is possible 52 // that some replies from the host never arrive, e.g., the corresponding 53 // renderer crashes. In that case, we have to clean up the callbacks, 54 // otherwise this object will live forever. 55 callbacks_.clear(); 56} 57 58void PluginResource::NotifyInstanceWasDeleted() { 59 Resource::NotifyInstanceWasDeleted(); 60 61 // Please see comments in NotifyLastPluginRefWasDeleted() about why we must 62 // clean up the callbacks. 63 // It is possible that NotifyLastPluginRefWasDeleted() is never called for a 64 // resource. For example, those singleton-style resources such as 65 // GamepadResource never expose references to the plugin and thus won't 66 // receive a NotifyLastPluginRefWasDeleted() call. For those resources, we 67 // need to clean up callbacks when the instance goes away. 68 callbacks_.clear(); 69} 70 71void PluginResource::SendCreate(Destination dest, const IPC::Message& msg) { 72 if (dest == RENDERER) { 73 DCHECK(!sent_create_to_renderer_); 74 sent_create_to_renderer_ = true; 75 } else { 76 DCHECK(!sent_create_to_browser_); 77 sent_create_to_browser_ = true; 78 } 79 ResourceMessageCallParams params(pp_resource(), GetNextSequence()); 80 GetSender(dest)->Send( 81 new PpapiHostMsg_ResourceCreated(params, pp_instance(), msg)); 82} 83 84void PluginResource::Post(Destination dest, const IPC::Message& msg) { 85 ResourceMessageCallParams params(pp_resource(), GetNextSequence()); 86 SendResourceCall(dest, params, msg); 87} 88 89bool PluginResource::SendResourceCall( 90 Destination dest, 91 const ResourceMessageCallParams& call_params, 92 const IPC::Message& nested_msg) { 93 return GetSender(dest)->Send( 94 new PpapiHostMsg_ResourceCall(call_params, nested_msg)); 95} 96 97int32_t PluginResource::GenericSyncCall(Destination dest, 98 const IPC::Message& msg, 99 IPC::Message* reply) { 100 ResourceMessageCallParams params(pp_resource(), GetNextSequence()); 101 params.set_has_callback(); 102 ResourceMessageReplyParams reply_params; 103 bool success = GetSender(dest)->Send(new PpapiHostMsg_ResourceSyncCall( 104 params, msg, &reply_params, reply)); 105 if (success) 106 return reply_params.result(); 107 return PP_ERROR_FAILED; 108} 109 110int32_t PluginResource::GetNextSequence() { 111 // Return the value with wraparound, making sure we don't make a sequence 112 // number with a 0 ID. Note that signed wraparound is undefined in C++ so we 113 // manually check. 114 int32_t ret = next_sequence_number_; 115 if (next_sequence_number_ == std::numeric_limits<int32_t>::max()) 116 next_sequence_number_ = 1; // Skip 0 which is invalid. 117 else 118 next_sequence_number_++; 119 return ret; 120} 121 122} // namespace proxy 123} // namespace ppapi 124