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.
6 #include "base/memory/ref_counted.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/run_loop.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "base/threading/simple_thread.h"
11 #include "ppapi/c/pp_completion_callback.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/proxy/ppapi_proxy_test.h"
14 #include "ppapi/proxy/ppb_message_loop_proxy.h"
15 #include "ppapi/shared_impl/callback_tracker.h"
16 #include "ppapi/shared_impl/proxy_lock.h"
17 #include "ppapi/shared_impl/resource.h"
18 #include "ppapi/shared_impl/resource_tracker.h"
19 #include "ppapi/shared_impl/scoped_pp_resource.h"
20 #include "ppapi/shared_impl/test_globals.h"
21 #include "ppapi/shared_impl/tracked_callback.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 // Note, this file tests TrackedCallback which lives in ppapi/shared_impl.
25 // Unfortunately, we need the test to live in ppapi/proxy so that it can use
26 // the thread support there.
32 class CallbackThread
: public base::SimpleThread
{
34 explicit CallbackThread(PP_Instance instance
)
35 : SimpleThread("CallbackThread"), instance_(instance
) {}
36 ~CallbackThread() override
{}
38 // base::SimpleThread overrides.
39 void Start() override
{
41 ProxyAutoLock acquire
;
42 // Create the message loop here, after PpapiGlobals has been created.
43 message_loop_
= new MessageLoopResource(instance_
);
45 base::SimpleThread::Start();
47 void Join() override
{
49 ProxyAutoLock acquire
;
50 message_loop()->PostQuit(PP_TRUE
);
51 message_loop_
= nullptr;
53 base::SimpleThread::Join();
56 ProxyAutoLock acquire
;
57 // Make a local copy of message_loop_ for this thread so we can interact
58 // with it even after the main thread releases it.
59 scoped_refptr
<MessageLoopResource
> message_loop(message_loop_
);
60 message_loop
->AttachToCurrentThread();
61 // Note, run releases the lock to run events.
63 message_loop
->DetachFromThread();
66 MessageLoopResource
* message_loop() { return message_loop_
.get(); }
69 PP_Instance instance_
;
70 scoped_refptr
<MessageLoopResource
> message_loop_
;
73 class TrackedCallbackTest
: public PluginProxyTest
{
75 TrackedCallbackTest() : thread_(pp_instance()) {}
76 CallbackThread
& thread() { return thread_
; }
79 // PluginProxyTest overrides.
80 void SetUp() override
{
81 PluginProxyTest::SetUp();
84 void TearDown() override
{
86 PluginProxyTest::TearDown();
87 base::RunLoop run_loop
;
88 run_loop
.RunUntilIdle();
90 CallbackThread thread_
;
93 // All valid results (PP_OK, PP_ERROR_...) are nonpositive.
94 const int32_t kInitializedResultValue
= 1;
95 const int32_t kOverrideResultValue
= 2;
97 struct CallbackRunInfo
{
98 explicit CallbackRunInfo(base::ThreadChecker
* thread_checker
)
100 result_(kInitializedResultValue
),
101 completion_task_run_count_(0),
102 completion_task_result_(kInitializedResultValue
),
103 thread_checker_(thread_checker
),
104 callback_did_run_event_(true, false) {}
105 void CallbackDidRun(int32_t result
) {
106 CHECK(thread_checker_
->CalledOnValidThread());
110 callback_did_run_event_
.Signal();
112 void CompletionTaskDidRun(int32_t result
) {
113 CHECK(thread_checker_
->CalledOnValidThread());
114 if (!completion_task_run_count_
)
115 completion_task_result_
= result
;
116 ++completion_task_run_count_
;
118 void WaitUntilCompleted() { callback_did_run_event_
.Wait(); }
119 unsigned run_count() { return run_count_
; }
120 int32_t result() { return result_
; }
121 unsigned completion_task_run_count() { return completion_task_run_count_
; }
122 int32_t completion_task_result() { return completion_task_result_
; }
126 unsigned completion_task_run_count_
;
127 int32_t completion_task_result_
;
128 // Weak; owned by the creator of CallbackRunInfo.
129 base::ThreadChecker
* thread_checker_
;
131 base::WaitableEvent callback_did_run_event_
;
134 void TestCallback(void* user_data
, int32_t result
) {
135 CallbackRunInfo
* info
= static_cast<CallbackRunInfo
*>(user_data
);
136 info
->CallbackDidRun(result
);
139 // CallbackShutdownTest --------------------------------------------------------
141 class CallbackShutdownTest
: public TrackedCallbackTest
{
143 CallbackShutdownTest() : info_did_run_(&thread_checker_
),
144 info_did_abort_(&thread_checker_
),
145 info_didnt_run_(&thread_checker_
) {}
148 // (1) A callback which is run (so shouldn't be aborted on shutdown).
149 // (2) A callback which is aborted (so shouldn't be aborted on shutdown).
150 // (3) A callback which isn't run (so should be aborted on shutdown).
151 CallbackRunInfo
& info_did_run() { return info_did_run_
; } // (1)
152 CallbackRunInfo
& info_did_abort() { return info_did_abort_
; } // (2)
153 CallbackRunInfo
& info_didnt_run() { return info_didnt_run_
; } // (3)
156 base::ThreadChecker thread_checker_
;
157 CallbackRunInfo info_did_run_
;
158 CallbackRunInfo info_did_abort_
;
159 CallbackRunInfo info_didnt_run_
;
164 // Tests that callbacks are properly aborted on module shutdown.
165 TEST_F(CallbackShutdownTest
, AbortOnShutdown
) {
167 scoped_refptr
<Resource
> resource(
168 new Resource(OBJECT_IS_PROXY
, pp_instance()));
170 // Set up case (1) (see above).
171 EXPECT_EQ(0U, info_did_run().run_count());
172 // TODO(dmichael): Test this on a background thread?
173 scoped_refptr
<TrackedCallback
> callback_did_run
= new TrackedCallback(
175 PP_MakeCompletionCallback(&TestCallback
, &info_did_run()));
176 EXPECT_EQ(0U, info_did_run().run_count());
177 callback_did_run
->Run(PP_OK
);
178 EXPECT_EQ(1U, info_did_run().run_count());
179 EXPECT_EQ(PP_OK
, info_did_run().result());
182 EXPECT_EQ(0U, info_did_abort().run_count());
183 scoped_refptr
<TrackedCallback
> callback_did_abort
= new TrackedCallback(
185 PP_MakeCompletionCallback(&TestCallback
, &info_did_abort()));
186 EXPECT_EQ(0U, info_did_abort().run_count());
187 callback_did_abort
->Abort();
188 EXPECT_EQ(1U, info_did_abort().run_count());
189 EXPECT_EQ(PP_ERROR_ABORTED
, info_did_abort().result());
192 EXPECT_EQ(0U, info_didnt_run().run_count());
193 scoped_refptr
<TrackedCallback
> callback_didnt_run
= new TrackedCallback(
195 PP_MakeCompletionCallback(&TestCallback
, &info_didnt_run()));
196 EXPECT_EQ(0U, info_didnt_run().run_count());
198 GetGlobals()->GetCallbackTrackerForInstance(pp_instance())->AbortAll();
201 EXPECT_EQ(1U, info_did_run().run_count());
204 EXPECT_EQ(1U, info_did_abort().run_count());
207 EXPECT_EQ(1U, info_didnt_run().run_count());
208 EXPECT_EQ(PP_ERROR_ABORTED
, info_didnt_run().result());
211 // CallbackResourceTest --------------------------------------------------------
215 class CallbackResourceTest
: public TrackedCallbackTest
{
217 CallbackResourceTest() {}
220 class CallbackMockResource
: public Resource
{
222 static scoped_refptr
<CallbackMockResource
> Create(PP_Instance instance
) {
223 ProxyAutoLock acquire
;
224 return scoped_refptr
<CallbackMockResource
>(
225 new CallbackMockResource(instance
));
227 ~CallbackMockResource() {}
229 // Take a reference to this resource, which will add it to the tracker.
231 ProxyAutoLock acquire
;
232 ScopedPPResource
temp_resource(ScopedPPResource::PassRef(), GetReference());
233 EXPECT_NE(0, temp_resource
.get());
234 reference_holder_
= temp_resource
;
236 // Release it, removing it from the tracker.
238 ProxyAutoLock acquire
;
239 reference_holder_
= 0;
242 // Create the test callbacks on a background thread, so that we can verify
243 // they are run on the same thread where they were created.
244 void CreateCallbacksOnLoop(MessageLoopResource
* loop_resource
) {
245 ProxyAutoLock acquire
;
246 // |thread_checker_| will bind to the background thread.
247 thread_checker_
.DetachFromThread();
248 loop_resource
->message_loop_proxy()->PostTask(FROM_HERE
,
250 base::Bind(&CallbackMockResource::CreateCallbacks
, this)));
253 int32_t CompletionTask(CallbackRunInfo
* info
, int32_t result
) {
254 // The completion task must run on the thread where the callback was
255 // created, and must hold the proxy lock.
256 CHECK(thread_checker_
.CalledOnValidThread());
257 ProxyLock::AssertAcquired();
259 // We should run before the callback.
260 CHECK_EQ(0U, info
->run_count());
261 info
->CompletionTaskDidRun(result
);
262 return kOverrideResultValue
;
265 void CheckInitialState() {
266 callbacks_created_event_
.Wait();
267 EXPECT_EQ(0U, info_did_run_
.run_count());
268 EXPECT_EQ(0U, info_did_run_
.completion_task_run_count());
270 EXPECT_EQ(0U, info_did_run_with_completion_task_
.run_count());
272 info_did_run_with_completion_task_
.completion_task_run_count());
274 EXPECT_EQ(0U, info_did_abort_
.run_count());
275 EXPECT_EQ(0U, info_did_abort_
.completion_task_run_count());
277 EXPECT_EQ(0U, info_didnt_run_
.run_count());
278 EXPECT_EQ(0U, info_didnt_run_
.completion_task_run_count());
281 void RunCallbacks() {
282 callback_did_run_
->Run(PP_OK
);
283 callback_did_run_with_completion_task_
->Run(PP_OK
);
284 callback_did_abort_
->Abort();
285 info_did_run_
.WaitUntilCompleted();
286 info_did_run_with_completion_task_
.WaitUntilCompleted();
287 info_did_abort_
.WaitUntilCompleted();
290 void CheckIntermediateState() {
291 EXPECT_EQ(1U, info_did_run_
.run_count());
292 EXPECT_EQ(PP_OK
, info_did_run_
.result());
293 EXPECT_EQ(0U, info_did_run_
.completion_task_run_count());
295 EXPECT_EQ(1U, info_did_run_with_completion_task_
.run_count());
296 // completion task should override the result.
297 EXPECT_EQ(kOverrideResultValue
,
298 info_did_run_with_completion_task_
.result());
300 info_did_run_with_completion_task_
.completion_task_run_count());
302 info_did_run_with_completion_task_
.completion_task_result());
304 EXPECT_EQ(1U, info_did_abort_
.run_count());
305 // completion task shouldn't override an abort.
306 EXPECT_EQ(PP_ERROR_ABORTED
, info_did_abort_
.result());
307 EXPECT_EQ(1U, info_did_abort_
.completion_task_run_count());
308 EXPECT_EQ(PP_ERROR_ABORTED
, info_did_abort_
.completion_task_result());
310 EXPECT_EQ(0U, info_didnt_run_
.completion_task_run_count());
311 EXPECT_EQ(0U, info_didnt_run_
.run_count());
314 void CheckFinalState() {
315 info_didnt_run_
.WaitUntilCompleted();
316 EXPECT_EQ(1U, info_did_run_with_completion_task_
.run_count());
317 EXPECT_EQ(kOverrideResultValue
,
318 info_did_run_with_completion_task_
.result());
319 callback_did_run_with_completion_task_
= nullptr;
320 EXPECT_EQ(1U, info_did_run_
.run_count());
321 EXPECT_EQ(PP_OK
, info_did_run_
.result());
322 callback_did_run_
= nullptr;
323 EXPECT_EQ(1U, info_did_abort_
.run_count());
324 EXPECT_EQ(PP_ERROR_ABORTED
, info_did_abort_
.result());
325 callback_did_abort_
= nullptr;
326 EXPECT_EQ(1U, info_didnt_run_
.run_count());
327 EXPECT_EQ(PP_ERROR_ABORTED
, info_didnt_run_
.result());
328 callback_didnt_run_
= nullptr;
332 explicit CallbackMockResource(PP_Instance instance
)
333 : Resource(OBJECT_IS_PROXY
, instance
),
334 info_did_run_(&thread_checker_
),
335 info_did_run_with_completion_task_(&thread_checker_
),
336 info_did_abort_(&thread_checker_
),
337 info_didnt_run_(&thread_checker_
),
338 callbacks_created_event_(true, false) {}
339 void CreateCallbacks() {
340 // Bind thread_checker_ to the thread where we create the callbacks.
341 // Later, when the callback runs, it will check that it was invoked on this
343 CHECK(thread_checker_
.CalledOnValidThread());
345 callback_did_run_
= new TrackedCallback(
346 this, PP_MakeCompletionCallback(&TestCallback
, &info_did_run_
));
348 // In order to test that the completion task can override the callback
349 // result, we need to test callbacks with and without a completion task.
350 callback_did_run_with_completion_task_
= new TrackedCallback(
352 PP_MakeCompletionCallback(&TestCallback
,
353 &info_did_run_with_completion_task_
));
354 callback_did_run_with_completion_task_
->set_completion_task(
355 Bind(&CallbackMockResource::CompletionTask
,
357 &info_did_run_with_completion_task_
));
359 callback_did_abort_
= new TrackedCallback(
360 this, PP_MakeCompletionCallback(&TestCallback
, &info_did_abort_
));
361 callback_did_abort_
->set_completion_task(
362 Bind(&CallbackMockResource::CompletionTask
, this, &info_did_abort_
));
364 callback_didnt_run_
= new TrackedCallback(
365 this, PP_MakeCompletionCallback(&TestCallback
, &info_didnt_run_
));
366 callback_didnt_run_
->set_completion_task(
367 Bind(&CallbackMockResource::CompletionTask
, this, &info_didnt_run_
));
369 callbacks_created_event_
.Signal();
372 // Used to verify that the callback runs on the same thread where it is
374 base::ThreadChecker thread_checker_
;
376 scoped_refptr
<TrackedCallback
> callback_did_run_
;
377 CallbackRunInfo info_did_run_
;
379 scoped_refptr
<TrackedCallback
> callback_did_run_with_completion_task_
;
380 CallbackRunInfo info_did_run_with_completion_task_
;
382 scoped_refptr
<TrackedCallback
> callback_did_abort_
;
383 CallbackRunInfo info_did_abort_
;
385 scoped_refptr
<TrackedCallback
> callback_didnt_run_
;
386 CallbackRunInfo info_didnt_run_
;
388 base::WaitableEvent callbacks_created_event_
;
390 ScopedPPResource reference_holder_
;
395 // Test that callbacks get aborted on the last resource unref.
396 TEST_F(CallbackResourceTest
, AbortOnNoRef
) {
397 // Test several things: Unref-ing a resource (to zero refs) with callbacks
398 // which (1) have been run, (2) have been aborted, (3) haven't been completed.
399 // Check that the uncompleted one gets aborted, and that the others don't get
401 scoped_refptr
<CallbackMockResource
> resource_1(
402 CallbackMockResource::Create(pp_instance()));
403 resource_1
->CreateCallbacksOnLoop(thread().message_loop());
404 resource_1
->CheckInitialState();
405 resource_1
->RunCallbacks();
406 resource_1
->TakeRef();
407 resource_1
->CheckIntermediateState();
409 // Also do the same for a second resource, and make sure that unref-ing the
410 // first resource doesn't much up the second resource.
411 scoped_refptr
<CallbackMockResource
> resource_2(
412 CallbackMockResource::Create(pp_instance()));
413 resource_2
->CreateCallbacksOnLoop(thread().message_loop());
414 resource_2
->CheckInitialState();
415 resource_2
->RunCallbacks();
416 resource_2
->TakeRef();
417 resource_2
->CheckIntermediateState();
419 // Double-check that resource #1 is still okay.
420 resource_1
->CheckIntermediateState();
422 // Kill resource #1, spin the message loop to run posted calls, and check that
423 // things are in the expected states.
424 resource_1
->ReleaseRef();
426 resource_1
->CheckFinalState();
427 resource_2
->CheckIntermediateState();
430 resource_2
->ReleaseRef();
432 resource_1
->CheckFinalState();
433 resource_2
->CheckFinalState();
437 resource_1
= nullptr;
438 resource_2
= nullptr;
442 // Test that "resurrecting" a resource (getting a new ID for a |Resource|)
443 // doesn't resurrect callbacks.
444 TEST_F(CallbackResourceTest
, Resurrection
) {
445 scoped_refptr
<CallbackMockResource
> resource(
446 CallbackMockResource::Create(pp_instance()));
447 resource
->CreateCallbacksOnLoop(thread().message_loop());
448 resource
->CheckInitialState();
449 resource
->RunCallbacks();
451 resource
->CheckIntermediateState();
453 // Unref it and check that things are in the expected states.
454 resource
->ReleaseRef();
455 resource
->CheckFinalState();
457 // "Resurrect" it and check that the callbacks are still dead.
459 resource
->CheckFinalState();
461 // Unref it again and do the same.
462 resource
->ReleaseRef();
463 resource
->CheckFinalState();