blob: 3a5513d7ccfe6a1468028d588041d8a3aac674b7 [file] [log] [blame]
[email protected]73097562012-01-12 19:38:551// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]f24448db2011-01-27 20:40:392// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
avie029c4132015-12-23 06:45:225#include <stdint.h>
[email protected]f24448db2011-01-27 20:40:396
avie029c4132015-12-23 06:45:227#include "ppapi/proxy/ppapi_proxy_test.h"
dmichael64d576c2015-01-27 21:00:128#include "ppapi/proxy/proxy_object_var.h"
[email protected]f24448db2011-01-27 20:40:399#include "ppapi/proxy/serialized_var.h"
[email protected]4c41d3f2012-02-15 01:44:4710#include "ppapi/shared_impl/proxy_lock.h"
[email protected]f24448db2011-01-27 20:40:3911
[email protected]4d2efd22011-08-18 21:58:0212namespace ppapi {
[email protected]f24448db2011-01-27 20:40:3913namespace proxy {
14
15namespace {
16
[email protected]f24448db2011-01-27 20:40:3917PP_Var MakeObjectVar(int64_t object_id) {
18 PP_Var ret;
19 ret.type = PP_VARTYPE_OBJECT;
20 ret.value.as_id = object_id;
21 return ret;
22}
23
24class SerializedVarTest : public PluginProxyTest {
25 public:
26 SerializedVarTest() {}
27};
28
29} // namespace
30
[email protected]7d6fd8a2011-08-01 18:13:5431// Tests output arguments in the plugin. This is when the host calls into the
32// plugin and the plugin returns something via an out param, like an exception.
[email protected]a732cec2011-12-22 08:35:5233TEST_F(SerializedVarTest, PluginSerializedVarInOutParam) {
[email protected]4c41d3f2012-02-15 01:44:4734 ProxyAutoLock lock;
[email protected]a732cec2011-12-22 08:35:5235 PP_Var host_object = MakeObjectVar(0x31337);
36
37 PP_Var plugin_object;
38 {
39 // Receive the object param, we should be tracking it with no refcount, and
40 // no messages sent.
41 SerializedVarTestConstructor input(host_object);
42 SerializedVarReceiveInput receive_input(input);
43 plugin_object = receive_input.Get(plugin_dispatcher());
44 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
45 EXPECT_EQ(0u, sink().message_count());
46
47 SerializedVar sv;
48 {
49 // The "OutParam" does its work in its destructor, it will write the
50 // information to the SerializedVar we passed in the constructor.
51 SerializedVarOutParam out_param(&sv);
52 // An out-param needs to pass a reference to the caller, so it's the
53 // responsibility of the plugin to bump the ref-count on an input
54 // parameter.
55 var_tracker().AddRefVar(plugin_object);
56 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
57 // We should have informed the host that a reference was taken.
58 EXPECT_EQ(1u, sink().message_count());
59 *out_param.OutParam(plugin_dispatcher()) = plugin_object;
60 }
61
62 // The object should have transformed the plugin object back to the host
63 // object ID. Nothing in the var tracker should have changed yet, and no
64 // messages should have been sent.
65 SerializedVarTestReader reader(sv);
[email protected]2d449b32012-02-07 05:38:0066 EXPECT_EQ(host_object.value.as_id, reader.GetVar().value.as_id);
[email protected]a732cec2011-12-22 08:35:5267 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
68 EXPECT_EQ(1u, sink().message_count());
69 }
70
71 // The out param should have done an "end receive caller owned" on the plugin
72 // var serialization rules, which should have released the "track-with-no-
73 // reference" count in the var tracker as well as the 1 reference we passed
74 // back to the host, so the object should no longer be in the tracker. The
75 // reference we added has been removed, so another message should be sent to
76 // the host to tell it we're done with the object.
77 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
78 EXPECT_EQ(2u, sink().message_count());
79}
80
81// Tests output strings in the plugin. This is when the host calls into the
82// plugin with a string and the plugin returns it via an out param.
83TEST_F(SerializedVarTest, PluginSerializedStringVarInOutParam) {
[email protected]4c41d3f2012-02-15 01:44:4784 ProxyAutoLock lock;
[email protected]a732cec2011-12-22 08:35:5285 PP_Var plugin_string;
86 const std::string kTestString("elite");
87 {
88 // Receive the string param. We should track it with 1 refcount.
89 SerializedVarTestConstructor input(kTestString);
90 SerializedVarReceiveInput receive_input(input);
91 plugin_string = receive_input.Get(plugin_dispatcher());
92 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_string));
93 EXPECT_EQ(0u, sink().message_count());
94
95 SerializedVar sv;
96 {
97 // The "OutParam" does its work in its destructor, it will write the
98 // information to the SerializedVar we passed in the constructor.
99 SerializedVarOutParam out_param(&sv);
100 // An out-param needs to pass a reference to the caller, so it's the
101 // responsibility of the plugin to bump the ref-count of an input
102 // parameter.
103 var_tracker().AddRefVar(plugin_string);
104 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string));
105 EXPECT_EQ(0u, sink().message_count());
106 *out_param.OutParam(plugin_dispatcher()) = plugin_string;
107 }
108
109 // The SerializedVar should have set the string value internally. Nothing in
110 // the var tracker should have changed yet, and no messages should have been
111 // sent.
112 SerializedVarTestReader reader(sv);
[email protected]2d449b32012-02-07 05:38:00113 //EXPECT_EQ(kTestString, *reader.GetTrackerStringPtr());
[email protected]a732cec2011-12-22 08:35:52114 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string));
115 EXPECT_EQ(0u, sink().message_count());
116 }
117 // The reference the string had initially should be gone, and the reference we
118 // passed to the host should also be gone, so the string should be removed.
119 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_string));
120 EXPECT_EQ(0u, sink().message_count());
121}
122
[email protected]73097562012-01-12 19:38:55123// Tests receiving an argument and passing it back to the browser as an output
124// parameter.
[email protected]f24448db2011-01-27 20:40:39125TEST_F(SerializedVarTest, PluginSerializedVarOutParam) {
[email protected]4c41d3f2012-02-15 01:44:47126 ProxyAutoLock lock;
[email protected]f24448db2011-01-27 20:40:39127 PP_Var host_object = MakeObjectVar(0x31337);
128
129 // Start tracking this object in the plugin.
130 PP_Var plugin_object = var_tracker().ReceiveObjectPassRef(
131 host_object, plugin_dispatcher());
132 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
133
134 {
135 SerializedVar sv;
136 {
137 // The "OutParam" does its work in its destructor, it will write the
138 // information to the SerializedVar we passed in the constructor.
139 SerializedVarOutParam out_param(&sv);
140 *out_param.OutParam(plugin_dispatcher()) = plugin_object;
141 }
142
143 // The object should have transformed the plugin object back to the host
144 // object ID. Nothing in the var tracker should have changed yet, and no
145 // messages should have been sent.
146 SerializedVarTestReader reader(sv);
[email protected]2d449b32012-02-07 05:38:00147 EXPECT_EQ(host_object.value.as_id, reader.GetVar().value.as_id);
[email protected]f24448db2011-01-27 20:40:39148 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
149 EXPECT_EQ(0u, sink().message_count());
150 }
151
152 // The out param should have done an "end send pass ref" on the plugin
153 // var serialization rules, which should have in turn released the reference
154 // in the var tracker. Since we only had one reference, this should have sent
155 // a release to the browser.
156 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
157 EXPECT_EQ(1u, sink().message_count());
158
159 // We don't bother validating that message since it's nontrivial and the
160 // PluginVarTracker test has cases that cover that this message is correct.
161}
162
[email protected]7d6fd8a2011-08-01 18:13:54163// Tests the case that the plugin receives the same var twice as an input
164// parameter (not passing ownership).
165TEST_F(SerializedVarTest, PluginReceiveInput) {
[email protected]4c41d3f2012-02-15 01:44:47166 ProxyAutoLock lock;
[email protected]7d6fd8a2011-08-01 18:13:54167 PP_Var host_object = MakeObjectVar(0x31337);
168
169 PP_Var plugin_object;
170 {
171 // Receive the first param, we should be tracking it with no refcount, and
172 // no messages sent.
173 SerializedVarTestConstructor input1(host_object);
174 SerializedVarReceiveInput receive_input(input1);
175 plugin_object = receive_input.Get(plugin_dispatcher());
176 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
177 EXPECT_EQ(0u, sink().message_count());
178
179 // Receive the second param, it should be resolved to the same plugin
180 // object and there should still be no refcount.
181 SerializedVarTestConstructor input2(host_object);
182 SerializedVarReceiveInput receive_input2(input2);
183 PP_Var plugin_object2 = receive_input2.Get(plugin_dispatcher());
184 EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
185 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
186 EXPECT_EQ(0u, sink().message_count());
187
188 // Take a reference to the object, as if the plugin was using it, and then
189 // release it, we should still be tracking the object since the
190 // ReceiveInputs keep the "track_with_no_reference_count" alive until
191 // they're destroyed.
[email protected]2bbd2c672011-08-09 23:14:13192 var_tracker().AddRefVar(plugin_object);
[email protected]7d6fd8a2011-08-01 18:13:54193 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
[email protected]2bbd2c672011-08-09 23:14:13194 var_tracker().ReleaseVar(plugin_object);
[email protected]7d6fd8a2011-08-01 18:13:54195 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
196 EXPECT_EQ(2u, sink().message_count());
197 }
198
199 // Since we didn't keep any refs to the objects, it should have freed the
200 // object.
201 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
202}
203
[email protected]a732cec2011-12-22 08:35:52204// Tests the case that the plugin receives the same vars twice as an input
205// parameter (not passing ownership) within a vector.
[email protected]ecac5732012-10-06 02:06:21206TEST_F(SerializedVarTest, PluginVectorReceiveInput) {
[email protected]4c41d3f2012-02-15 01:44:47207 ProxyAutoLock lock;
[email protected]a732cec2011-12-22 08:35:52208 PP_Var host_object = MakeObjectVar(0x31337);
209
[email protected]ecac5732012-10-06 02:06:21210 std::vector<PP_Var> plugin_objects;
211 std::vector<PP_Var> plugin_objects2;
[email protected]a732cec2011-12-22 08:35:52212 {
213 // Receive the params. The object should be tracked with no refcount and
214 // no messages sent. The string should is plugin-side only and should have
215 // a reference-count of 1.
216 std::vector<SerializedVar> input1;
217 input1.push_back(SerializedVarTestConstructor(host_object));
218 input1.push_back(SerializedVarTestConstructor("elite"));
219 SerializedVarVectorReceiveInput receive_input(input1);
220 uint32_t array_size = 0;
[email protected]ecac5732012-10-06 02:06:21221 PP_Var* plugin_objects_array =
222 receive_input.Get(plugin_dispatcher(), &array_size);
223 plugin_objects.insert(plugin_objects.begin(), plugin_objects_array,
224 plugin_objects_array + array_size);
[email protected]a732cec2011-12-22 08:35:52225 ASSERT_EQ(2u, array_size);
226 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
227 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1]));
228 EXPECT_EQ(0u, sink().message_count());
229
230 // Receive the second param, it should be resolved to the same plugin
231 // object and there should still be no refcount.
232 std::vector<SerializedVar> input2;
233 input2.push_back(SerializedVarTestConstructor(host_object));
234 input2.push_back(SerializedVarTestConstructor("elite"));
235 SerializedVarVectorReceiveInput receive_input2(input2);
236 uint32_t array_size2 = 0;
[email protected]ecac5732012-10-06 02:06:21237 PP_Var* plugin_objects_array2 =
238 receive_input2.Get(plugin_dispatcher(), &array_size2);
239 plugin_objects2.insert(plugin_objects2.begin(), plugin_objects_array2,
240 plugin_objects_array2 + array_size2);
[email protected]a732cec2011-12-22 08:35:52241 ASSERT_EQ(2u, array_size2);
242 EXPECT_EQ(plugin_objects[0].value.as_id, plugin_objects2[0].value.as_id);
243 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
244 // Strings get re-created with a new ID. We don't try to reuse strings in
245 // the tracker, so the string should get a new ID.
246 EXPECT_NE(plugin_objects[1].value.as_id, plugin_objects2[1].value.as_id);
247 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects2[1]));
248 EXPECT_EQ(0u, sink().message_count());
249
250 // Take a reference to the object, as if the plugin was using it, and then
251 // release it, we should still be tracking the object since the
252 // ReceiveInputs keep the "track_with_no_reference_count" alive until
253 // they're destroyed.
254 var_tracker().AddRefVar(plugin_objects[0]);
255 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[0]));
256 var_tracker().ReleaseVar(plugin_objects[0]);
257 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
258 EXPECT_EQ(2u, sink().message_count());
259
260 // Take a reference to a string and then release it. Make sure no messages
261 // are sent.
brettw669d47b12015-02-13 21:17:38262 uint32_t old_message_count = static_cast<uint32_t>(sink().message_count());
[email protected]a732cec2011-12-22 08:35:52263 var_tracker().AddRefVar(plugin_objects[1]);
264 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_objects[1]));
265 var_tracker().ReleaseVar(plugin_objects[1]);
266 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1]));
267 EXPECT_EQ(old_message_count, sink().message_count());
268 }
269
270 // Since we didn't keep any refs to the objects or strings, so they should
271 // have been freed.
272 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[0]));
273 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[1]));
274 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects2[1]));
275}
276
dmichael64d576c2015-01-27 21:00:12277// Tests the browser sending a String var as a return value to make sure we
278// ref-count the host side properly.
279typedef HostProxyTest HostSerializedVarTest;
280TEST_F(HostSerializedVarTest, PluginReceiveStringReturn) {
281 {
282 PP_Var string_var = StringVar::StringToPPVar("Hello");
283 EXPECT_EQ(1, var_tracker().GetRefCountForObject(string_var));
284 GetDispatcher()->serialization_rules()->BeginSendPassRef(string_var);
285 GetDispatcher()->serialization_rules()->EndSendPassRef(string_var);
286 // It should be gone, so we should get -1 to indicate that.
287 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(string_var));
288 }
289
290 {
291 // Note this is as little weird; we're testing the behavior of the host-
292 // side of the proxy, but we use ProxyObjectVar, because this unit test
293 // doesn't have access to stuff in content/renderer/pepper. The ref-counting
294 // behavior should be the same, however. All we're really testing
295 // is the code in ppapi/proxy (HostVarSerializationRules).
296 scoped_refptr<Var> obj_var = new ProxyObjectVar(NULL, 1234);
297 PP_Var obj_pp_var = obj_var->GetPPVar();
298 EXPECT_EQ(1, var_tracker().GetRefCountForObject(obj_pp_var));
299 GetDispatcher()->serialization_rules()->BeginSendPassRef(obj_pp_var);
300 GetDispatcher()->serialization_rules()->EndSendPassRef(obj_pp_var);
301 // The host side for object vars always keeps 1 ref on behalf of the plugin.
302 // See HostVarSerializationRules and PluginVarSerializationRules for an
303 // explanation.
304 EXPECT_EQ(1, var_tracker().GetRefCountForObject(obj_pp_var));
305 var_tracker().ReleaseVar(obj_pp_var);
306 }
307}
308
[email protected]7d6fd8a2011-08-01 18:13:54309// Tests the plugin receiving a var as a return value from the browser
310// two different times (passing ownership).
311TEST_F(SerializedVarTest, PluginReceiveReturn) {
[email protected]4c41d3f2012-02-15 01:44:47312 ProxyAutoLock lock;
[email protected]7d6fd8a2011-08-01 18:13:54313 PP_Var host_object = MakeObjectVar(0x31337);
314
315 PP_Var plugin_object;
316 {
317 // Receive the first param, we should be tracking it with a refcount of 1.
318 SerializedVarTestConstructor input1(host_object);
319 ReceiveSerializedVarReturnValue receive_input(input1);
320 plugin_object = receive_input.Return(plugin_dispatcher());
321 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
322 EXPECT_EQ(0u, sink().message_count());
323
324 // Receive the second param, it should be resolved to the same plugin
325 // object and there should be a plugin refcount of 2. There should have
326 // been an IPC message sent that released the duplicated ref in the browser
327 // (so both of our refs are represented by one in the browser).
328 SerializedVarTestConstructor input2(host_object);
329 ReceiveSerializedVarReturnValue receive_input2(input2);
330 PP_Var plugin_object2 = receive_input2.Return(plugin_dispatcher());
331 EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
332 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
333 EXPECT_EQ(1u, sink().message_count());
334 }
335
336 // The ReceiveSerializedVarReturnValue destructor shouldn't have affected
337 // the refcount or sent any messages.
338 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
339 EXPECT_EQ(1u, sink().message_count());
340
341 // Manually release one refcount, it shouldn't have sent any more messages.
[email protected]2bbd2c672011-08-09 23:14:13342 var_tracker().ReleaseVar(plugin_object);
[email protected]7d6fd8a2011-08-01 18:13:54343 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
344 EXPECT_EQ(1u, sink().message_count());
345
346 // Manually release the last refcount, it should have freed it and sent a
347 // release message to the browser.
[email protected]2bbd2c672011-08-09 23:14:13348 var_tracker().ReleaseVar(plugin_object);
[email protected]7d6fd8a2011-08-01 18:13:54349 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
350 EXPECT_EQ(2u, sink().message_count());
351}
352
353// Returns a value from the browser to the plugin, then return that one ref
354// back to the browser.
355TEST_F(SerializedVarTest, PluginReturnValue) {
[email protected]4c41d3f2012-02-15 01:44:47356 ProxyAutoLock lock;
[email protected]7d6fd8a2011-08-01 18:13:54357 PP_Var host_object = MakeObjectVar(0x31337);
358
359 PP_Var plugin_object;
360 {
361 // Receive the param in the plugin.
362 SerializedVarTestConstructor input1(host_object);
363 ReceiveSerializedVarReturnValue receive_input(input1);
364 plugin_object = receive_input.Return(plugin_dispatcher());
365 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
366 EXPECT_EQ(0u, sink().message_count());
367 }
368
369 {
370 // Now return to the browser.
371 SerializedVar output;
372 SerializedVarReturnValue return_output(&output);
373 return_output.Return(plugin_dispatcher(), plugin_object);
374
375 // The ref in the plugin should be alive until the ReturnValue goes out of
376 // scope, since the release needs to be after the browser processes the
377 // message.
378 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
379 }
380
381 // When the ReturnValue object goes out of scope, it should have sent a
382 // release message to the browser.
383 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
384 EXPECT_EQ(1u, sink().message_count());
385}
386
[email protected]f24448db2011-01-27 20:40:39387} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02388} // namespace ppapi