OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/bind.h" | |
6 #include "base/message_loop.h" | |
7 #include "base/test/test_timeouts.h" | |
8 #include "base/time.h" | |
9 #include "ppapi/c/dev/ppb_var_deprecated.h" | 5 #include "ppapi/c/dev/ppb_var_deprecated.h" |
10 #include "ppapi/c/dev/ppp_class_deprecated.h" | 6 #include "ppapi/c/dev/ppp_class_deprecated.h" |
11 #include "ppapi/c/pp_var.h" | 7 #include "ppapi/c/pp_var.h" |
12 #include "ppapi/c/ppb_var.h" | 8 #include "ppapi/c/ppb_var.h" |
13 #include "ppapi/c/ppp_instance.h" | 9 #include "ppapi/c/ppp_instance.h" |
14 #include "ppapi/c/private/ppp_instance_private.h" | 10 #include "ppapi/c/private/ppp_instance_private.h" |
15 #include "ppapi/proxy/host_dispatcher.h" | 11 #include "ppapi/proxy/host_dispatcher.h" |
16 #include "ppapi/proxy/ppapi_proxy_test.h" | 12 #include "ppapi/proxy/ppapi_proxy_test.h" |
17 #include "ppapi/shared_impl/ppb_var_shared.h" | |
18 #include "ppapi/shared_impl/var.h" | |
19 | 13 |
20 namespace ppapi { | 14 namespace ppapi { |
21 | |
22 // A fake version of NPObjectVar for testing. | |
23 class NPObjectVar : public ppapi::Var { | |
24 public: | |
25 NPObjectVar() {} | |
26 virtual ~NPObjectVar() {} | |
27 | |
28 // Var overrides. | |
29 virtual NPObjectVar* AsNPObjectVar() OVERRIDE { return this; } | |
30 virtual PP_VarType GetType() const OVERRIDE { return PP_VARTYPE_OBJECT; } | |
31 }; | |
32 | |
33 namespace proxy { | 15 namespace proxy { |
34 | 16 |
35 namespace { | 17 namespace { |
36 const PP_Instance kInstance = 0xdeadbeef; | 18 const PP_Instance kInstance = 0xdeadbeef; |
37 | 19 |
38 PP_Var GetPPVarNoAddRef(Var* var) { | 20 PP_Var MakeObjectVar(int64_t object_id) { |
39 PP_Var var_to_return = var->GetPPVar(); | 21 PP_Var ret; |
40 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(var_to_return); | 22 ret.type = PP_VARTYPE_OBJECT; |
41 return var_to_return; | 23 ret.value.as_id = object_id; |
| 24 return ret; |
42 } | 25 } |
43 | 26 |
44 PluginDispatcher* plugin_dispatcher = NULL; | 27 PluginDispatcher* plugin_dispatcher = NULL; |
45 // Return the plugin-side proxy for PPB_Var_Deprecated. | 28 // Return the plugin-side proxy for PPB_Var_Deprecated. |
46 const PPB_Var_Deprecated* plugin_var_deprecated_if() { | 29 const PPB_Var_Deprecated* plugin_var_deprecated_if() { |
47 // The test code must set the plugin dispatcher. | 30 // The test code must set the plugin dispatcher. |
48 CHECK(plugin_dispatcher); | 31 CHECK(plugin_dispatcher); |
49 // Grab the plugin-side proxy for PPB_Var_Deprecated (for CreateObject). | 32 // Grab the plugin-side proxy for PPB_Var_Deprecated (for CreateObject). |
50 return static_cast<const PPB_Var_Deprecated*>( | 33 return static_cast<const PPB_Var_Deprecated*>( |
51 plugin_dispatcher->GetBrowserInterface( | 34 plugin_dispatcher->GetBrowserInterface( |
52 PPB_VAR_DEPRECATED_INTERFACE)); | 35 PPB_VAR_DEPRECATED_INTERFACE)); |
53 } | 36 } |
54 | 37 |
55 // Mock PPP_Instance_Private. | 38 // Mock PPP_Instance_Private. |
56 PP_Var instance_obj; | 39 PP_Var instance_obj; |
57 PP_Var GetInstanceObject(PP_Instance /*instance*/) { | 40 PP_Var GetInstanceObject(PP_Instance /*instance*/) { |
58 // The 1 ref we got from CreateObject will be passed to the host. We want to | 41 // The 1 ref we got from CreateObject will be passed to the host. We want to |
59 // have a ref of our own. | 42 // have a ref of our own. |
60 printf("GetInstanceObject called\n"); | 43 plugin_var_deprecated_if()->AddRef(instance_obj); |
61 PpapiGlobals::Get()->GetVarTracker()->AddRefVar(instance_obj); | |
62 return instance_obj; | 44 return instance_obj; |
63 } | 45 } |
64 | 46 |
65 PPP_Instance_Private ppp_instance_private_mock = { | 47 PPP_Instance_Private ppp_instance_private_mock = { |
66 &GetInstanceObject | 48 &GetInstanceObject |
67 }; | 49 }; |
68 | 50 |
69 // We need to mock PPP_Instance, so that we can create and destroy the pretend | 51 // We need to mock PPP_Instance, so that we can create and destroy the pretend |
70 // instance that PPP_Instance_Private uses. | 52 // instance that PPP_Instance_Private uses. |
71 PP_Bool DidCreate(PP_Instance /*instance*/, uint32_t /*argc*/, | 53 PP_Bool DidCreate(PP_Instance /*instance*/, uint32_t /*argc*/, |
72 const char* /*argn*/[], const char* /*argv*/[]) { | 54 const char* /*argn*/[], const char* /*argv*/[]) { |
73 // Create an object var. This should exercise the typical path for creating | 55 // Create an object var. This should exercise the typical path for creating |
74 // instance objects. | 56 // instance objects. |
75 instance_obj = | 57 instance_obj = |
76 plugin_var_deprecated_if()->CreateObject(kInstance, NULL, NULL); | 58 plugin_var_deprecated_if()->CreateObject(kInstance, NULL, NULL); |
77 return PP_TRUE; | 59 return PP_TRUE; |
78 } | 60 } |
79 | 61 |
80 void DidDestroy(PP_Instance /*instance*/) { | 62 void DidDestroy(PP_Instance /*instance*/) { |
81 // Decrement the reference count for our instance object. It should be | 63 // Decrement the reference count for our instance object. It should be |
82 // deleted. | 64 // deleted. |
83 plugin_var_deprecated_if()->Release(instance_obj); | 65 plugin_var_deprecated_if()->Release(instance_obj); |
84 } | 66 } |
85 | 67 |
86 PPP_Instance_1_0 ppp_instance_mock = { &DidCreate, &DidDestroy }; | 68 PPP_Instance_1_0 ppp_instance_mock = { &DidCreate, &DidDestroy }; |
87 | 69 |
| 70 } // namespace |
| 71 |
88 // Mock PPB_Var_Deprecated, so that we can emulate creating an Object Var. | 72 // Mock PPB_Var_Deprecated, so that we can emulate creating an Object Var. |
89 PP_Var CreateObject(PP_Instance /*instance*/, | 73 std::map<int64_t, int> id_refcount_map; |
| 74 void AddRefVar(PP_Var var) { |
| 75 CHECK(var.type >= PP_VARTYPE_STRING); // Must be a ref-counted type. |
| 76 CHECK(id_refcount_map.find(var.value.as_id) != id_refcount_map.end()); |
| 77 ++id_refcount_map[var.value.as_id]; |
| 78 } |
| 79 |
| 80 void ReleaseVar(PP_Var var) { |
| 81 CHECK(var.type >= PP_VARTYPE_STRING); // Must be a ref-counted type. |
| 82 std::map<int64_t, int>::iterator iter = id_refcount_map.find(var.value.as_id); |
| 83 CHECK(iter != id_refcount_map.end()); |
| 84 CHECK(iter->second > 0); |
| 85 if (--(iter->second) == 0) |
| 86 id_refcount_map.erase(iter); |
| 87 } |
| 88 |
| 89 PP_Var CreateObject(PP_Instance instance, |
90 const PPP_Class_Deprecated* /*ppp_class*/, | 90 const PPP_Class_Deprecated* /*ppp_class*/, |
91 void* /*ppp_class_data*/) { | 91 void* /*ppp_class_data*/) { |
92 NPObjectVar* obj_var = new NPObjectVar; | 92 static int64_t last_id = 0; |
93 return obj_var->GetPPVar(); | 93 ++last_id; |
| 94 // Set the refcount to 0. It should really be 1, but that ref gets passed to |
| 95 // the plugin immediately (and we don't emulate all of that behavior here). |
| 96 id_refcount_map[last_id] = 0; |
| 97 return MakeObjectVar(last_id); |
94 } | 98 } |
95 | 99 |
96 const PPB_Var_Deprecated ppb_var_deprecated_mock = { | 100 const PPB_Var_Deprecated ppb_var_deprecated_mock = { |
97 PPB_Var_Shared::GetVarInterface1_0()->AddRef, | 101 &AddRefVar, |
98 PPB_Var_Shared::GetVarInterface1_0()->Release, | 102 &ReleaseVar, |
99 PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8, | 103 NULL, // VarFromUtf8 |
100 PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8, | 104 NULL, // VarToUtf8 |
101 NULL, // HasProperty | 105 NULL, // HasProperty |
102 NULL, // HasMethod | 106 NULL, // HasMethod |
103 NULL, // GetProperty | 107 NULL, // GetProperty |
104 NULL, // EnumerateProperties | 108 NULL, // EnumerateProperties |
105 NULL, // SetProperty | 109 NULL, // SetProperty |
106 NULL, // RemoveProperty | 110 NULL, // RemoveProperty |
107 NULL, // Call | 111 NULL, // Call |
108 NULL, // Construct | 112 NULL, // Construct |
109 NULL, // IsInstanceOf | 113 NULL, // IsInstanceOf |
110 &CreateObject | 114 &CreateObject |
111 }; | 115 }; |
112 | 116 |
113 } // namespace | 117 const PPB_Var ppb_var_mock = { &AddRefVar, &ReleaseVar }; |
114 | 118 |
115 class PPP_Instance_Private_ProxyTest : public TwoWayTest { | 119 class PPP_Instance_Private_ProxyTest : public TwoWayTest { |
116 public: | 120 public: |
117 PPP_Instance_Private_ProxyTest() | 121 PPP_Instance_Private_ProxyTest() |
118 : TwoWayTest(TwoWayTest::TEST_PPP_INTERFACE) { | 122 : TwoWayTest(TwoWayTest::TEST_PPP_INTERFACE) { |
119 plugin().RegisterTestInterface(PPP_INSTANCE_PRIVATE_INTERFACE, | 123 plugin().RegisterTestInterface(PPP_INSTANCE_PRIVATE_INTERFACE, |
120 &ppp_instance_private_mock); | 124 &ppp_instance_private_mock); |
121 plugin().RegisterTestInterface(PPP_INSTANCE_INTERFACE_1_0, | 125 plugin().RegisterTestInterface(PPP_INSTANCE_INTERFACE_1_0, |
122 &ppp_instance_mock); | 126 &ppp_instance_mock); |
123 host().RegisterTestInterface(PPB_VAR_DEPRECATED_INTERFACE, | 127 host().RegisterTestInterface(PPB_VAR_DEPRECATED_INTERFACE, |
124 &ppb_var_deprecated_mock); | 128 &ppb_var_deprecated_mock); |
| 129 host().RegisterTestInterface(PPB_VAR_INTERFACE, |
| 130 &ppb_var_mock); |
125 } | 131 } |
126 }; | 132 }; |
127 | 133 |
128 TEST_F(PPP_Instance_Private_ProxyTest, PPPInstancePrivate) { | 134 TEST_F(PPP_Instance_Private_ProxyTest, PPPInstancePrivate) { |
129 // This test controls its own instance; we can't use the one that | 135 // This test controls its own instance; we can't use the one that |
130 // PluginProxyTestHarness provides. | 136 // PluginProxyTestHarness provides. |
131 ASSERT_NE(kInstance, pp_instance()); | 137 ASSERT_NE(kInstance, pp_instance()); |
132 HostDispatcher::SetForInstance(kInstance, host().host_dispatcher()); | 138 HostDispatcher::SetForInstance(kInstance, host().host_dispatcher()); |
133 | 139 |
134 // This file-local global is used by the PPP_Instance mock above in order to | 140 // This file-local global is used by the PPP_Instance mock above in order to |
135 // access PPB_Var_Deprecated. | 141 // access PPB_Var_Deprecated. |
136 plugin_dispatcher = plugin().plugin_dispatcher(); | 142 plugin_dispatcher = plugin().plugin_dispatcher(); |
137 | 143 |
138 // Grab the host-side proxy for PPP_Instance and PPP_Instance_Private. | 144 // Grab the host-side proxy for PPP_Instance and PPP_Instance_Private. |
139 const PPP_Instance_Private* ppp_instance_private = | 145 const PPP_Instance_Private* ppp_instance_private = |
140 static_cast<const PPP_Instance_Private*>( | 146 static_cast<const PPP_Instance_Private*>( |
141 host().host_dispatcher()->GetProxiedInterface( | 147 host().host_dispatcher()->GetProxiedInterface( |
142 PPP_INSTANCE_PRIVATE_INTERFACE)); | 148 PPP_INSTANCE_PRIVATE_INTERFACE)); |
143 const PPP_Instance_1_1* ppp_instance = static_cast<const PPP_Instance_1_1*>( | 149 const PPP_Instance_1_0* ppp_instance = static_cast<const PPP_Instance_1_0*>( |
144 host().host_dispatcher()->GetProxiedInterface( | 150 host().host_dispatcher()->GetProxiedInterface( |
145 PPP_INSTANCE_INTERFACE_1_1)); | 151 PPP_INSTANCE_INTERFACE_1_0)); |
146 | 152 |
147 // Initialize an Instance, so that the plugin-side machinery will work | 153 // Initialize an Instance, so that the plugin-side machinery will work |
148 // properly. | 154 // properly. |
149 EXPECT_EQ(PP_TRUE, ppp_instance->DidCreate(kInstance, 0, NULL, NULL)); | 155 EXPECT_EQ(PP_TRUE, ppp_instance->DidCreate(kInstance, 0, NULL, NULL)); |
150 | 156 |
| 157 // Now instance_obj is valid and should have a ref-count of 1. |
| 158 PluginVarTracker& plugin_var_tracker = |
| 159 *PluginGlobals::Get()->plugin_var_tracker(); |
151 // Check the plugin-side reference count. | 160 // Check the plugin-side reference count. |
152 EXPECT_EQ(1, plugin().var_tracker().GetRefCountForObject(instance_obj)); | 161 EXPECT_EQ(1, plugin_var_tracker.GetRefCountForObject(instance_obj)); |
153 // Check the host-side var exists with the expected id and has 1 refcount (the | 162 // Check the host-side var and reference count. |
154 // refcount on behalf of the plugin). | 163 ASSERT_EQ(1u, id_refcount_map.size()); |
155 int32 expected_host_id = | 164 EXPECT_EQ(plugin_var_tracker.GetHostObject(instance_obj).value.as_id, |
156 plugin().var_tracker().GetHostObject(instance_obj).value.as_id; | 165 id_refcount_map.begin()->first); |
157 Var* host_var = host().var_tracker().GetVar(expected_host_id); | 166 EXPECT_EQ(0, id_refcount_map.begin()->second); |
158 ASSERT_TRUE(host_var); | |
159 EXPECT_EQ( | |
160 1, | |
161 host().var_tracker().GetRefCountForObject(GetPPVarNoAddRef(host_var))); | |
162 | 167 |
163 // Call from the browser side to get the instance object. | 168 // Call from the browser side to get the instance object. |
164 PP_Var host_pp_var = ppp_instance_private->GetInstanceObject(kInstance); | 169 PP_Var host_obj = ppp_instance_private->GetInstanceObject(kInstance); |
165 EXPECT_EQ(instance_obj.type, host_pp_var.type); | 170 EXPECT_EQ(instance_obj.type, host_obj.type); |
166 EXPECT_EQ(host_pp_var.value.as_id, expected_host_id); | 171 EXPECT_EQ(host_obj.value.as_id, |
167 EXPECT_EQ(1, plugin().var_tracker().GetRefCountForObject(instance_obj)); | 172 plugin_var_tracker.GetHostObject(instance_obj).value.as_id); |
168 // A reference is passed to the browser, which we consume here. | 173 EXPECT_EQ(1, plugin_var_tracker.GetRefCountForObject(instance_obj)); |
169 host().var_tracker().ReleaseVar(host_pp_var); | 174 ASSERT_EQ(1u, id_refcount_map.size()); |
170 EXPECT_EQ(1, host().var_tracker().GetRefCountForObject(host_pp_var)); | 175 // The browser should be passed a reference. |
| 176 EXPECT_EQ(1, id_refcount_map.begin()->second); |
171 | 177 |
172 // The plugin is going away; generally, so will all references to its instance | 178 // The plugin is going away; generally, so will all references to its instance |
173 // object. | 179 // object. |
174 host().var_tracker().ReleaseVar(host_pp_var); | 180 ReleaseVar(host_obj); |
175 // Destroy the instance. DidDestroy above decrements the reference count for | 181 // Destroy the instance. DidDestroy above decrements the reference count for |
176 // instance_obj, so it should also be destroyed. | 182 // instance_obj, so it should also be destroyed. |
177 ppp_instance->DidDestroy(kInstance); | 183 ppp_instance->DidDestroy(kInstance); |
178 EXPECT_EQ(-1, plugin().var_tracker().GetRefCountForObject(instance_obj)); | 184 EXPECT_EQ(-1, plugin_var_tracker.GetRefCountForObject(instance_obj)); |
179 EXPECT_EQ(-1, host().var_tracker().GetRefCountForObject(host_pp_var)); | 185 // Check the host-side reference count. |
| 186 EXPECT_EQ(0u, id_refcount_map.size()); |
180 } | 187 } |
181 | 188 |
182 } // namespace proxy | 189 } // namespace proxy |
183 } // namespace ppapi | 190 } // namespace ppapi |
184 | 191 |
OLD | NEW |