• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PluginResource(Connection connection,PP_Instance instance)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 
~PluginResource()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 
OnReplyReceived(const proxy::ResourceMessageReplyParams & params,const IPC::Message & msg)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 
NotifyLastPluginRefWasDeleted()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 
NotifyInstanceWasDeleted()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 
SendCreate(Destination dest,const IPC::Message & msg)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 
AttachToPendingHost(Destination dest,int pending_host_id)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 
Post(Destination dest,const IPC::Message & msg)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 
SendResourceCall(Destination dest,const ResourceMessageCallParams & call_params,const IPC::Message & nested_msg)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 
GenericSyncCall(Destination dest,const IPC::Message & msg,IPC::Message * reply,ResourceMessageReplyParams * reply_params)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 
GetNextSequence()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