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