• 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 #ifndef PPAPI_PROXY_ENTER_PROXY_H_
6 #define PPAPI_PROXY_ENTER_PROXY_H_
7 
8 #include "base/logging.h"
9 #include "ppapi/cpp/completion_callback.h"
10 #include "ppapi/proxy/host_dispatcher.h"
11 #include "ppapi/proxy/plugin_dispatcher.h"
12 #include "ppapi/proxy/plugin_globals.h"
13 #include "ppapi/proxy/plugin_resource_tracker.h"
14 #include "ppapi/thunk/enter.h"
15 
16 namespace ppapi {
17 
18 namespace proxy {
19 
20 // Wrapper around EnterResourceNoLock that takes a host resource. This is used
21 // when handling messages in the plugin from the host and we need to convert to
22 // an object in the plugin side corresponding to that.
23 //
24 // This never locks since we assume the host Resource is coming from IPC, and
25 // never logs errors since we assume the host is doing reasonable things.
26 template<typename ResourceT>
27 class EnterPluginFromHostResource
28     : public thunk::EnterResourceNoLock<ResourceT> {
29  public:
EnterPluginFromHostResource(const HostResource & host_resource)30   explicit EnterPluginFromHostResource(const HostResource& host_resource)
31       : thunk::EnterResourceNoLock<ResourceT>(
32             PluginGlobals::Get()->plugin_resource_tracker()->
33                 PluginResourceForHostResource(host_resource),
34             false) {
35     // Validate that we're in the plugin rather than the host. Otherwise this
36     // object will do the wrong thing. In the plugin, the instance should have
37     // a corresponding plugin dispatcher (assuming the resource is valid).
38     DCHECK(this->failed() ||
39            PluginDispatcher::GetForInstance(host_resource.instance()));
40   }
41 };
42 
43 template<typename ResourceT>
44 class EnterHostFromHostResource
45     : public thunk::EnterResourceNoLock<ResourceT> {
46  public:
EnterHostFromHostResource(const HostResource & host_resource)47   explicit EnterHostFromHostResource(const HostResource& host_resource)
48       : thunk::EnterResourceNoLock<ResourceT>(host_resource.host_resource(),
49                                               false) {
50     // Validate that we're in the host rather than the plugin. Otherwise this
51     // object will do the wrong thing. In the host, the instance should have
52     // a corresponding host disptacher (assuming the resource is valid).
53     DCHECK(this->failed() ||
54            HostDispatcher::GetForInstance(host_resource.instance()));
55   }
56 
EnterHostFromHostResource(const HostResource & host_resource,const pp::CompletionCallback & callback)57   EnterHostFromHostResource(const HostResource& host_resource,
58                             const pp::CompletionCallback& callback)
59       : thunk::EnterResourceNoLock<ResourceT>(host_resource.host_resource(),
60                                               callback.pp_completion_callback(),
61                                               false) {
62     // Validate that we're in the host rather than the plugin. Otherwise this
63     // object will do the wrong thing. In the host, the instance should have
64     // a corresponding host disptacher (assuming the resource is valid).
65     DCHECK(this->failed() ||
66            HostDispatcher::GetForInstance(host_resource.instance()));
67   }
68 };
69 
70 // Enters a resource and forces a completion callback to be issued.
71 //
72 // This is used when implementing the host (renderer) side of a resource
73 // function that issues a completion callback. In all cases, we need to issue
74 // the callback to avoid hanging the plugin.
75 //
76 // This class automatically constructs a callback with the given factory
77 // calling the given method. The method will generally be the one that sends
78 // the message to trigger the completion callback in the plugin process.
79 //
80 // It will automatically issue the callback with PP_ERROR_NOINTERFACE if the
81 // host resource is invalid (i.e. failed() is set). In all other cases you
82 // should call SetResult(), which will issue the callback immediately if the
83 // result value isn't PP_OK_COMPLETIONPENDING. In the "completion pending"
84 // case, it's assumed the function the proxy is calling will take responsibility
85 // of executing the callback (returned by callback()).
86 //
87 // Example:
88 //   EnterHostFromHostResourceForceCallback<PPB_Foo_API> enter(
89 //       resource, callback_factory_, &MyClass::SendResult, resource);
90 //   if (enter.failed())
91 //     return;  // SendResult automatically called with PP_ERROR_BADRESOURCE.
92 //   enter.SetResult(enter.object()->DoFoo(enter.callback()));
93 //
94 // Where DoFoo's signature looks like this:
95 //   int32_t DoFoo(PP_CompletionCallback callback);
96 // And SendResult's implementation looks like this:
97 //   void MyClass::SendResult(int32_t result, const HostResource& res) {
98 //     Send(new FooMsg_FooComplete(..., result, res));
99 //   }
100 template<typename ResourceT>
101 class EnterHostFromHostResourceForceCallback
102     : public EnterHostFromHostResource<ResourceT> {
103  public:
EnterHostFromHostResourceForceCallback(const HostResource & host_resource,const pp::CompletionCallback & callback)104   EnterHostFromHostResourceForceCallback(
105       const HostResource& host_resource,
106       const pp::CompletionCallback& callback)
107       : EnterHostFromHostResource<ResourceT>(host_resource, callback),
108         needs_running_(true) {
109   }
110 
111   // For callbacks that take no parameters except the "int32_t result". Most
112   // implementations will use the 1-extra-argument constructor below.
113   template<class CallbackFactory, typename Method>
EnterHostFromHostResourceForceCallback(const HostResource & host_resource,CallbackFactory & factory,Method method)114   EnterHostFromHostResourceForceCallback(
115       const HostResource& host_resource,
116       CallbackFactory& factory,
117       Method method)
118       : EnterHostFromHostResource<ResourceT>(host_resource,
119             factory.NewOptionalCallback(method)),
120         needs_running_(true) {
121     if (this->failed())
122       RunCallback(PP_ERROR_BADRESOURCE);
123   }
124 
125   // For callbacks that take an extra parameter as a closure.
126   template<class CallbackFactory, typename Method, typename A>
EnterHostFromHostResourceForceCallback(const HostResource & host_resource,CallbackFactory & factory,Method method,const A & a)127   EnterHostFromHostResourceForceCallback(
128       const HostResource& host_resource,
129       CallbackFactory& factory,
130       Method method,
131       const A& a)
132       : EnterHostFromHostResource<ResourceT>(host_resource,
133             factory.NewOptionalCallback(method, a)),
134         needs_running_(true) {
135     if (this->failed())
136       RunCallback(PP_ERROR_BADRESOURCE);
137   }
138 
139   // For callbacks that take two extra parameters as a closure.
140   template<class CallbackFactory, typename Method, typename A, typename B>
EnterHostFromHostResourceForceCallback(const HostResource & host_resource,CallbackFactory & factory,Method method,const A & a,const B & b)141   EnterHostFromHostResourceForceCallback(
142       const HostResource& host_resource,
143       CallbackFactory& factory,
144       Method method,
145       const A& a,
146       const B& b)
147       : EnterHostFromHostResource<ResourceT>(host_resource,
148             factory.NewOptionalCallback(method, a, b)),
149         needs_running_(true) {
150     if (this->failed())
151       RunCallback(PP_ERROR_BADRESOURCE);
152   }
153 
154   // For callbacks that take three extra parameters as a closure.
155   template<class CallbackFactory, typename Method, typename A, typename B,
156            typename C>
EnterHostFromHostResourceForceCallback(const HostResource & host_resource,CallbackFactory & factory,Method method,const A & a,const B & b,const C & c)157   EnterHostFromHostResourceForceCallback(
158       const HostResource& host_resource,
159       CallbackFactory& factory,
160       Method method,
161       const A& a,
162       const B& b,
163       const C& c)
164       : EnterHostFromHostResource<ResourceT>(host_resource,
165             factory.NewOptionalCallback(method, a, b, c)),
166         needs_running_(true) {
167     if (this->failed())
168       RunCallback(PP_ERROR_BADRESOURCE);
169   }
170 
~EnterHostFromHostResourceForceCallback()171   ~EnterHostFromHostResourceForceCallback() {
172     if (needs_running_) {
173       NOTREACHED() << "Should always call SetResult except in the "
174                       "initialization failed case.";
175       RunCallback(PP_ERROR_FAILED);
176     }
177   }
178 
SetResult(int32_t result)179   void SetResult(int32_t result) {
180     DCHECK(needs_running_) << "Don't call SetResult when there already is one.";
181     if (result != PP_OK_COMPLETIONPENDING)
182       RunCallback(result);
183     needs_running_ = false;
184     // Either we already ran the callback, or it will be run asynchronously. We
185     // clear the callback so it isn't accidentally run again (and because
186     // EnterBase checks that the callback has been cleared).
187     this->ClearCallback();
188   }
189 
190  private:
RunCallback(int32_t result)191   void RunCallback(int32_t result) {
192     DCHECK(needs_running_);
193     needs_running_ = false;
194     this->callback()->Run(result);
195     this->ClearCallback();
196   }
197 
198   bool needs_running_;
199 };
200 
201 }  // namespace proxy
202 }  // namespace ppapi
203 
204 #endif  // PPAPI_PROXY_ENTER_PROXY_H_
205