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.
5 #include "ppapi/proxy/ppapi_proxy_test.h"
7 #include "ppapi/proxy/serialized_var.h"
8 #include "ppapi/shared_impl/proxy_lock.h"
15 PP_Var
MakeObjectVar(int64_t object_id
) {
17 ret
.type
= PP_VARTYPE_OBJECT
;
18 ret
.value
.as_id
= object_id
;
22 class SerializedVarTest
: public PluginProxyTest
{
24 SerializedVarTest() {}
29 // Tests output arguments in the plugin. This is when the host calls into the
30 // plugin and the plugin returns something via an out param, like an exception.
31 TEST_F(SerializedVarTest
, PluginSerializedVarInOutParam
) {
33 PP_Var host_object
= MakeObjectVar(0x31337);
37 // Receive the object param, we should be tracking it with no refcount, and
39 SerializedVarTestConstructor
input(host_object
);
40 SerializedVarReceiveInput
receive_input(input
);
41 plugin_object
= receive_input
.Get(plugin_dispatcher());
42 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object
));
43 EXPECT_EQ(0u, sink().message_count());
47 // The "OutParam" does its work in its destructor, it will write the
48 // information to the SerializedVar we passed in the constructor.
49 SerializedVarOutParam
out_param(&sv
);
50 // An out-param needs to pass a reference to the caller, so it's the
51 // responsibility of the plugin to bump the ref-count on an input
53 var_tracker().AddRefVar(plugin_object
);
54 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object
));
55 // We should have informed the host that a reference was taken.
56 EXPECT_EQ(1u, sink().message_count());
57 *out_param
.OutParam(plugin_dispatcher()) = plugin_object
;
60 // The object should have transformed the plugin object back to the host
61 // object ID. Nothing in the var tracker should have changed yet, and no
62 // messages should have been sent.
63 SerializedVarTestReader
reader(sv
);
64 EXPECT_EQ(host_object
.value
.as_id
, reader
.GetVar().value
.as_id
);
65 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object
));
66 EXPECT_EQ(1u, sink().message_count());
69 // The out param should have done an "end receive caller owned" on the plugin
70 // var serialization rules, which should have released the "track-with-no-
71 // reference" count in the var tracker as well as the 1 reference we passed
72 // back to the host, so the object should no longer be in the tracker. The
73 // reference we added has been removed, so another message should be sent to
74 // the host to tell it we're done with the object.
75 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object
));
76 EXPECT_EQ(2u, sink().message_count());
79 // Tests output strings in the plugin. This is when the host calls into the
80 // plugin with a string and the plugin returns it via an out param.
81 TEST_F(SerializedVarTest
, PluginSerializedStringVarInOutParam
) {
84 const std::string
kTestString("elite");
86 // Receive the string param. We should track it with 1 refcount.
87 SerializedVarTestConstructor
input(kTestString
);
88 SerializedVarReceiveInput
receive_input(input
);
89 plugin_string
= receive_input
.Get(plugin_dispatcher());
90 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_string
));
91 EXPECT_EQ(0u, sink().message_count());
95 // The "OutParam" does its work in its destructor, it will write the
96 // information to the SerializedVar we passed in the constructor.
97 SerializedVarOutParam
out_param(&sv
);
98 // An out-param needs to pass a reference to the caller, so it's the
99 // responsibility of the plugin to bump the ref-count of an input
101 var_tracker().AddRefVar(plugin_string
);
102 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string
));
103 EXPECT_EQ(0u, sink().message_count());
104 *out_param
.OutParam(plugin_dispatcher()) = plugin_string
;
107 // The SerializedVar should have set the string value internally. Nothing in
108 // the var tracker should have changed yet, and no messages should have been
110 SerializedVarTestReader
reader(sv
);
111 //EXPECT_EQ(kTestString, *reader.GetTrackerStringPtr());
112 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string
));
113 EXPECT_EQ(0u, sink().message_count());
115 // The reference the string had initially should be gone, and the reference we
116 // passed to the host should also be gone, so the string should be removed.
117 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_string
));
118 EXPECT_EQ(0u, sink().message_count());
121 // Tests receiving an argument and passing it back to the browser as an output
123 TEST_F(SerializedVarTest
, PluginSerializedVarOutParam
) {
125 PP_Var host_object
= MakeObjectVar(0x31337);
127 // Start tracking this object in the plugin.
128 PP_Var plugin_object
= var_tracker().ReceiveObjectPassRef(
129 host_object
, plugin_dispatcher());
130 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object
));
135 // The "OutParam" does its work in its destructor, it will write the
136 // information to the SerializedVar we passed in the constructor.
137 SerializedVarOutParam
out_param(&sv
);
138 *out_param
.OutParam(plugin_dispatcher()) = plugin_object
;
141 // The object should have transformed the plugin object back to the host
142 // object ID. Nothing in the var tracker should have changed yet, and no
143 // messages should have been sent.
144 SerializedVarTestReader
reader(sv
);
145 EXPECT_EQ(host_object
.value
.as_id
, reader
.GetVar().value
.as_id
);
146 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object
));
147 EXPECT_EQ(0u, sink().message_count());
150 // The out param should have done an "end send pass ref" on the plugin
151 // var serialization rules, which should have in turn released the reference
152 // in the var tracker. Since we only had one reference, this should have sent
153 // a release to the browser.
154 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object
));
155 EXPECT_EQ(1u, sink().message_count());
157 // We don't bother validating that message since it's nontrivial and the
158 // PluginVarTracker test has cases that cover that this message is correct.
161 // Tests the case that the plugin receives the same var twice as an input
162 // parameter (not passing ownership).
163 TEST_F(SerializedVarTest
, PluginReceiveInput
) {
165 PP_Var host_object
= MakeObjectVar(0x31337);
167 PP_Var plugin_object
;
169 // Receive the first param, we should be tracking it with no refcount, and
171 SerializedVarTestConstructor
input1(host_object
);
172 SerializedVarReceiveInput
receive_input(input1
);
173 plugin_object
= receive_input
.Get(plugin_dispatcher());
174 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object
));
175 EXPECT_EQ(0u, sink().message_count());
177 // Receive the second param, it should be resolved to the same plugin
178 // object and there should still be no refcount.
179 SerializedVarTestConstructor
input2(host_object
);
180 SerializedVarReceiveInput
receive_input2(input2
);
181 PP_Var plugin_object2
= receive_input2
.Get(plugin_dispatcher());
182 EXPECT_EQ(plugin_object
.value
.as_id
, plugin_object2
.value
.as_id
);
183 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object
));
184 EXPECT_EQ(0u, sink().message_count());
186 // Take a reference to the object, as if the plugin was using it, and then
187 // release it, we should still be tracking the object since the
188 // ReceiveInputs keep the "track_with_no_reference_count" alive until
189 // they're destroyed.
190 var_tracker().AddRefVar(plugin_object
);
191 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object
));
192 var_tracker().ReleaseVar(plugin_object
);
193 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object
));
194 EXPECT_EQ(2u, sink().message_count());
197 // Since we didn't keep any refs to the objects, it should have freed the
199 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object
));
202 // Tests the case that the plugin receives the same vars twice as an input
203 // parameter (not passing ownership) within a vector.
204 TEST_F(SerializedVarTest
, PluginVectorReceiveInput
) {
206 PP_Var host_object
= MakeObjectVar(0x31337);
208 PP_Var
* plugin_objects
;
209 PP_Var
* plugin_objects2
;
211 // Receive the params. The object should be tracked with no refcount and
212 // no messages sent. The string should is plugin-side only and should have
213 // a reference-count of 1.
214 std::vector
<SerializedVar
> input1
;
215 input1
.push_back(SerializedVarTestConstructor(host_object
));
216 input1
.push_back(SerializedVarTestConstructor("elite"));
217 SerializedVarVectorReceiveInput
receive_input(input1
);
218 uint32_t array_size
= 0;
219 plugin_objects
= receive_input
.Get(plugin_dispatcher(), &array_size
);
220 ASSERT_EQ(2u, array_size
);
221 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects
[0]));
222 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects
[1]));
223 EXPECT_EQ(0u, sink().message_count());
225 // Receive the second param, it should be resolved to the same plugin
226 // object and there should still be no refcount.
227 std::vector
<SerializedVar
> input2
;
228 input2
.push_back(SerializedVarTestConstructor(host_object
));
229 input2
.push_back(SerializedVarTestConstructor("elite"));
230 SerializedVarVectorReceiveInput
receive_input2(input2
);
231 uint32_t array_size2
= 0;
232 plugin_objects2
= receive_input2
.Get(plugin_dispatcher(), &array_size2
);
233 ASSERT_EQ(2u, array_size2
);
234 EXPECT_EQ(plugin_objects
[0].value
.as_id
, plugin_objects2
[0].value
.as_id
);
235 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects
[0]));
236 // Strings get re-created with a new ID. We don't try to reuse strings in
237 // the tracker, so the string should get a new ID.
238 EXPECT_NE(plugin_objects
[1].value
.as_id
, plugin_objects2
[1].value
.as_id
);
239 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects2
[1]));
240 EXPECT_EQ(0u, sink().message_count());
242 // Take a reference to the object, as if the plugin was using it, and then
243 // release it, we should still be tracking the object since the
244 // ReceiveInputs keep the "track_with_no_reference_count" alive until
245 // they're destroyed.
246 var_tracker().AddRefVar(plugin_objects
[0]);
247 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects
[0]));
248 var_tracker().ReleaseVar(plugin_objects
[0]);
249 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects
[0]));
250 EXPECT_EQ(2u, sink().message_count());
252 // Take a reference to a string and then release it. Make sure no messages
254 uint32_t old_message_count
= sink().message_count();
255 var_tracker().AddRefVar(plugin_objects
[1]);
256 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_objects
[1]));
257 var_tracker().ReleaseVar(plugin_objects
[1]);
258 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects
[1]));
259 EXPECT_EQ(old_message_count
, sink().message_count());
262 // Since we didn't keep any refs to the objects or strings, so they should
264 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects
[0]));
265 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects
[1]));
266 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects2
[1]));
269 // Tests the plugin receiving a var as a return value from the browser
270 // two different times (passing ownership).
271 TEST_F(SerializedVarTest
, PluginReceiveReturn
) {
273 PP_Var host_object
= MakeObjectVar(0x31337);
275 PP_Var plugin_object
;
277 // Receive the first param, we should be tracking it with a refcount of 1.
278 SerializedVarTestConstructor
input1(host_object
);
279 ReceiveSerializedVarReturnValue
receive_input(input1
);
280 plugin_object
= receive_input
.Return(plugin_dispatcher());
281 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object
));
282 EXPECT_EQ(0u, sink().message_count());
284 // Receive the second param, it should be resolved to the same plugin
285 // object and there should be a plugin refcount of 2. There should have
286 // been an IPC message sent that released the duplicated ref in the browser
287 // (so both of our refs are represented by one in the browser).
288 SerializedVarTestConstructor
input2(host_object
);
289 ReceiveSerializedVarReturnValue
receive_input2(input2
);
290 PP_Var plugin_object2
= receive_input2
.Return(plugin_dispatcher());
291 EXPECT_EQ(plugin_object
.value
.as_id
, plugin_object2
.value
.as_id
);
292 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object
));
293 EXPECT_EQ(1u, sink().message_count());
296 // The ReceiveSerializedVarReturnValue destructor shouldn't have affected
297 // the refcount or sent any messages.
298 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object
));
299 EXPECT_EQ(1u, sink().message_count());
301 // Manually release one refcount, it shouldn't have sent any more messages.
302 var_tracker().ReleaseVar(plugin_object
);
303 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object
));
304 EXPECT_EQ(1u, sink().message_count());
306 // Manually release the last refcount, it should have freed it and sent a
307 // release message to the browser.
308 var_tracker().ReleaseVar(plugin_object
);
309 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object
));
310 EXPECT_EQ(2u, sink().message_count());
313 // Returns a value from the browser to the plugin, then return that one ref
314 // back to the browser.
315 TEST_F(SerializedVarTest
, PluginReturnValue
) {
317 PP_Var host_object
= MakeObjectVar(0x31337);
319 PP_Var plugin_object
;
321 // Receive the param in the plugin.
322 SerializedVarTestConstructor
input1(host_object
);
323 ReceiveSerializedVarReturnValue
receive_input(input1
);
324 plugin_object
= receive_input
.Return(plugin_dispatcher());
325 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object
));
326 EXPECT_EQ(0u, sink().message_count());
330 // Now return to the browser.
331 SerializedVar output
;
332 SerializedVarReturnValue
return_output(&output
);
333 return_output
.Return(plugin_dispatcher(), plugin_object
);
335 // The ref in the plugin should be alive until the ReturnValue goes out of
336 // scope, since the release needs to be after the browser processes the
338 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object
));
341 // When the ReturnValue object goes out of scope, it should have sent a
342 // release message to the browser.
343 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object
));
344 EXPECT_EQ(1u, sink().message_count());