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
3 // found in the LICENSE file.
4
5 #define UNIT_TEST // To get the ShadowingAtExitManager.
6 #include "base/at_exit.h"
7
8 #include "content/test/plugin/plugin_thread_async_call_test.h"
9
10 #include "base/bind.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/strings/string_util.h"
13 #include "base/threading/thread.h"
14 #include "content/test/plugin/plugin_client.h"
15
16 namespace NPAPIClient {
17
18 namespace {
19
20 // There are two plugin instances in this test. The long lived instance is used
21 // for reporting errors and signalling test completion. The short lived one is
22 // used to verify that async callbacks are not invoked after NPP_Destroy.
23 PluginThreadAsyncCallTest* g_short_lived_instance;
24 PluginThreadAsyncCallTest* g_long_lived_instance;
25
OnCallSucceededHelper(void * data)26 void OnCallSucceededHelper(void* data) {
27 static_cast<PluginThreadAsyncCallTest*>(data)->OnCallSucceeded();
28 }
29
OnCallFailed(void * data)30 void OnCallFailed(void* data) {
31 g_long_lived_instance->SetError("Async callback invoked after NPP_Destroy");
32 }
33
OnCallCompletedHelper(void * data)34 void OnCallCompletedHelper(void* data) {
35 static_cast<PluginThreadAsyncCallTest*>(data)->OnCallCompleted();
36 }
37 }
38
PluginThreadAsyncCallTest(NPP id,NPNetscapeFuncs * host_functions)39 PluginThreadAsyncCallTest::PluginThreadAsyncCallTest(
40 NPP id, NPNetscapeFuncs *host_functions)
41 : PluginTest(id, host_functions), at_exit_manager_(NULL) {
42 }
43
~PluginThreadAsyncCallTest()44 PluginThreadAsyncCallTest::~PluginThreadAsyncCallTest() {
45 delete at_exit_manager_;
46 }
47
New(uint16 mode,int16 argc,const char * argn[],const char * argv[],NPSavedData * saved)48 NPError PluginThreadAsyncCallTest::New(
49 uint16 mode, int16 argc, const char* argn[], const char* argv[],
50 NPSavedData* saved) {
51 NPError error = PluginTest::New(mode, argc, argn, argv, saved);
52 if (error != NPERR_NO_ERROR)
53 return error;
54
55 // Determine whether this is the short lived instance.
56 for (int i = 0; i < argc; ++i) {
57 if (base::strcasecmp(argn[i], "short_lived") == 0) {
58 if (base::strcasecmp(argv[i], "true") == 0) {
59 g_short_lived_instance = this;
60 } else {
61 g_long_lived_instance = this;
62 }
63 }
64 }
65
66 // Schedule an async call that will succeed. Make sure to call that API from
67 // a different thread to fully test it.
68 if (this == g_short_lived_instance) {
69 // This is slightly complicated thanks to the Linux shared library build,
70 // which shares more compilation units between the NPAPI plug-in and
71 // the base code.
72 at_exit_manager_ = new base::ShadowingAtExitManager();
73 base::Thread random_thread("random_thread");
74 random_thread.Start();
75 random_thread.message_loop()->PostTask(
76 FROM_HERE, base::Bind(&PluginThreadAsyncCallTest::AsyncCall,
77 base::Unretained(this)));
78 }
79
80 return NPERR_NO_ERROR;
81 }
82
AsyncCall()83 void PluginThreadAsyncCallTest::AsyncCall() {
84 HostFunctions()->pluginthreadasynccall(id(), OnCallSucceededHelper, this);
85 }
86
OnCallSucceeded()87 void PluginThreadAsyncCallTest::OnCallSucceeded() {
88 // Delete the short lived instance.
89 NPIdentifier delete_id = HostFunctions()->getstringidentifier(
90 "deleteShortLivedInstance");
91
92 NPObject *window_obj = NULL;
93 HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
94
95 NPVariant result;
96 HostFunctions()->invoke(id(), window_obj, delete_id, NULL, 0, &result);
97 }
98
Destroy()99 NPError PluginThreadAsyncCallTest::Destroy() {
100 if (this == g_short_lived_instance) {
101 // Schedule an async call that should not be called.
102 HostFunctions()->pluginthreadasynccall(id(), OnCallFailed, NULL);
103
104 // Schedule an async call to end the test using the long lived instance.
105 HostFunctions()->pluginthreadasynccall(g_long_lived_instance->id(),
106 OnCallCompletedHelper,
107 g_long_lived_instance);
108 }
109
110 return NPERR_NO_ERROR;
111 }
112
OnCallCompleted()113 void PluginThreadAsyncCallTest::OnCallCompleted() {
114 SignalTestCompleted();
115 }
116
117 } // namespace NPAPIClient
118