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 16namespace NPAPIClient { 17 18namespace { 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. 23PluginThreadAsyncCallTest* g_short_lived_instance; 24PluginThreadAsyncCallTest* g_long_lived_instance; 25 26void OnCallSucceededHelper(void* data) { 27 static_cast<PluginThreadAsyncCallTest*>(data)->OnCallSucceeded(); 28} 29 30void OnCallFailed(void* data) { 31 g_long_lived_instance->SetError("Async callback invoked after NPP_Destroy"); 32} 33 34void OnCallCompletedHelper(void* data) { 35 static_cast<PluginThreadAsyncCallTest*>(data)->OnCallCompleted(); 36} 37} 38 39PluginThreadAsyncCallTest::PluginThreadAsyncCallTest( 40 NPP id, NPNetscapeFuncs *host_functions) 41 : PluginTest(id, host_functions), at_exit_manager_(NULL) { 42} 43 44PluginThreadAsyncCallTest::~PluginThreadAsyncCallTest() { 45 delete at_exit_manager_; 46} 47 48NPError 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 83void PluginThreadAsyncCallTest::AsyncCall() { 84 HostFunctions()->pluginthreadasynccall(id(), OnCallSucceededHelper, this); 85} 86 87void 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 99NPError 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 113void PluginThreadAsyncCallTest::OnCallCompleted() { 114 SignalTestCompleted(); 115} 116 117} // namespace NPAPIClient 118