Fix testshell to use the new callback commands, and shut down properly

This commit is contained in:
Ben Turner 2009-08-25 16:07:22 -07:00
Родитель 24b18f8473
Коммит 9d33531365
15 изменённых файлов: 520 добавлений и 143 удалений

Просмотреть файл

@ -6,6 +6,10 @@
#include "mozilla/ipc/TestShellChild.h"
#include "mozilla/XPCOM.h"
#include "nsXPFEComponentsCID.h"
#include "nsIAppStartup.h"
using namespace mozilla::ipc;
namespace mozilla {
@ -35,27 +39,49 @@ ContentProcessChild::Init(MessageLoop* aIOLoop, IPC::Channel* aChannel)
IFrameEmbeddingProtocolChild*
ContentProcessChild::IFrameEmbeddingConstructor(const MagicWindowHandle& hwnd)
{
return new TabChild(hwnd);
IFrameEmbeddingProtocolChild* iframe = new TabChild(hwnd);
if (iframe && mIFrames.AppendElement(iframe)) {
return iframe;
}
delete iframe;
return nsnull;
}
nsresult
ContentProcessChild::IFrameEmbeddingDestructor(IFrameEmbeddingProtocolChild* iframe)
{
delete iframe;
mIFrames.RemoveElement(iframe);
return NS_OK;
}
TestShellProtocolChild*
ContentProcessChild::TestShellConstructor()
{
return new TestShellChild();
TestShellProtocolChild* testshell = new TestShellChild();
if (testshell && mTestShells.AppendElement(testshell)) {
return testshell;
}
delete testshell;
return nsnull;
}
nsresult
ContentProcessChild::TestShellDestructor(TestShellProtocolChild* shell)
{
delete shell;
return NS_OK;
mTestShells.RemoveElement(shell);
return NS_OK;
}
void
ContentProcessChild::Quit()
{
mIFrames.Clear();
mTestShells.Clear();
nsCOMPtr<nsIAppStartup> appStartup(do_GetService(NS_APPSTARTUP_CONTRACTID));
if (appStartup) {
appStartup->Quit(nsIAppStartup::eForceQuit);
}
}
} // namespace dom

Просмотреть файл

@ -6,6 +6,9 @@
#include "mozilla/dom/ContentProcessProtocolChild.h"
#include "nsTArray.h"
#include "nsAutoPtr.h"
namespace mozilla {
namespace dom {
@ -26,12 +29,17 @@ public:
virtual IFrameEmbeddingProtocolChild* IFrameEmbeddingConstructor(const MagicWindowHandle& hwnd);
virtual nsresult IFrameEmbeddingDestructor(IFrameEmbeddingProtocolChild*);
virtual TestShellProtocolChild* TestShellConstructor();
virtual nsresult TestShellDestructor(TestShellProtocolChild*);
virtual TestShellProtocolChild* TestShellConstructor();
virtual nsresult TestShellDestructor(TestShellProtocolChild*);
void Quit();
private:
static ContentProcessChild* sSingleton;
nsTArray<nsAutoPtr<IFrameEmbeddingProtocolChild> > mIFrames;
nsTArray<nsAutoPtr<TestShellProtocolChild> > mTestShells;
DISALLOW_EVIL_CONSTRUCTORS(ContentProcessChild);
};

Просмотреть файл

@ -26,6 +26,10 @@
#include "base/message_pump_libevent.h"
#endif
#ifdef CHROMIUM_MOZILLA_BUILD
class DoWorkRunnable;
#endif
// A MessageLoop is used to process events for a particular thread. There is
// at most one MessageLoop instance per thread.
//
@ -57,7 +61,12 @@
// are stable and accessible before calling SetNestableTasksAllowed(true).
//
class MessageLoop : public base::MessagePump::Delegate {
public:
#ifdef CHROMIUM_MOZILLA_BUILD
friend class DoWorkRunnable;
#endif
public:
static void EnableHistogrammer(bool enable_histogrammer);
// A DestructionObserver is notified when the current MessageLoop is being

Просмотреть файл

@ -40,7 +40,11 @@
#include "mozilla/ipc/AsyncChannel.h"
#include "mozilla/ipc/GeckoThread.h"
#include "mozilla/dom/ContentProcessChild.h"
using mozilla::dom::ContentProcessChild;
#include "nsDebug.h"
#include "nsXULAppAPI.h"
template<>
struct RunnableMethodTraits<mozilla::ipc::AsyncChannel>
@ -49,6 +53,13 @@ struct RunnableMethodTraits<mozilla::ipc::AsyncChannel>
static void ReleaseCallee(mozilla::ipc::AsyncChannel* obj) { }
};
template<>
struct RunnableMethodTraits<ContentProcessChild>
{
static void RetainCallee(ContentProcessChild* obj) { }
static void ReleaseCallee(ContentProcessChild* obj) { }
};
namespace mozilla {
namespace ipc {
@ -143,6 +154,8 @@ AsyncChannel::OnDispatchMessage(const Message& msg)
void
AsyncChannel::OnMessageReceived(const Message& msg)
{
NS_ASSERTION(mChannelState != ChannelError, "Shouldn't get here!");
// wake up the worker, there's work to do
mWorkerLoop->PostTask(FROM_HERE,
NewRunnableMethod(this,
@ -159,10 +172,26 @@ AsyncChannel::OnChannelConnected(int32 peer_pid)
void
AsyncChannel::OnChannelError()
{
NS_WARNING("Channel error, quitting IO loop!");
// FIXME/cjones impl
mChannelState = ChannelError;
MessageLoop::current()->Quit();
if (XRE_GetProcessType() == GeckoProcessType_Default) {
// Parent process, one of our children died. Notify?
}
else {
// Child process, initiate quit sequence.
#ifdef DEBUG
// XXXbent this is totally out of place, but works for now.
mWorkerLoop->PostTask(FROM_HERE,
NewRunnableMethod(ContentProcessChild::GetSingleton(),
&ContentProcessChild::Quit));
// Must exit the IO loop, which will then join with the UI loop.
MessageLoop::current()->Quit();
#else
// Go ahead and abort here.
NS_DebugBreak(NS_DEBUG_ABORT, nsnull, nsnull, nsnull, 0);
#endif
}
}
void

Просмотреть файл

@ -69,10 +69,23 @@ TimerCallback(nsITimer* aTimer,
} /* anonymous namespace */
class DoWorkRunnable : public nsRunnable
{
public:
NS_IMETHOD Run() {
MessageLoop* loop = MessageLoop::current();
NS_ASSERTION(loop, "Shouldn't be null!");
if (loop) {
loop->DoWork();
}
return NS_OK;
}
};
MessagePump::MessagePump()
: mThread(nsnull)
{
mDummyEvent = new nsRunnable();
mDummyEvent = new DoWorkRunnable();
// I'm tired of adding OOM checks.
NS_ADDREF(mDummyEvent);
}

Просмотреть файл

@ -36,17 +36,24 @@
* ***** END LICENSE BLOCK ***** */
include protocol "ContentProcess.ipdl";
include protocol "TestShellCommand.ipdl";
namespace mozilla {
namespace ipc {
sync protocol TestShell
protocol TestShell
{
manager ContentProcess;
manages TestShellCommand;
child:
async SendCommand(nsString aCommand);
sync SendCommandWithResponse(nsString aCommand) returns (nsString aResponse);
ExecuteCommand(nsString aCommand);
TestShellCommand(nsString aCommand);
parent:
~TestShellCommand(nsString aResponse);
};
} // namespace ipc

Просмотреть файл

@ -39,21 +39,32 @@
#include "XPCShellEnvironment.h"
using mozilla::ipc::TestShellChild;
using mozilla::ipc::TestShellCommandProtocolChild;
using mozilla::ipc::XPCShellEnvironment;
TestShellChild::TestShellChild()
: mXPCShell(XPCShellEnvironment::CreateEnvironment())
: mXPCShell(nsnull)
{
XPCShellEnvironment* env = XPCShellEnvironment::CreateEnvironment();
if (env) {
if (env->DefineIPCCommands(this)) {
mXPCShell = env;
}
else {
XPCShellEnvironment::DestroyEnvironment(env);
}
}
}
TestShellChild::~TestShellChild()
{
if (mXPCShell) {
XPCShellEnvironment::DestroyEnvironment(mXPCShell);
}
}
nsresult
TestShellChild::RecvSendCommand(const nsString& aCommand)
TestShellChild::RecvExecuteCommand(const nsString& aCommand)
{
if (mXPCShell->IsQuitting()) {
NS_WARNING("Commands sent after quit command issued!");
@ -63,16 +74,39 @@ TestShellChild::RecvSendCommand(const nsString& aCommand)
return mXPCShell->EvaluateString(aCommand) ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
TestShellChild::RecvSendCommandWithResponse(const nsString& aCommand,
nsString* aResponse)
TestShellCommandProtocolChild*
TestShellChild::TestShellCommandConstructor(const nsString& aCommand)
{
return new TestShellCommandProtocolChild();
}
nsresult
TestShellChild::TestShellCommandDestructor(TestShellCommandProtocolChild* aCommand,
const nsString& aResponse)
{
NS_ENSURE_ARG_POINTER(aCommand);
delete aCommand;
return NS_OK;
}
nsresult
TestShellChild::RecvTestShellCommandConstructor(TestShellCommandProtocolChild* aActor,
const nsString& aCommand)
{
NS_ASSERTION(aActor, "Shouldn't be null!");
if (mXPCShell->IsQuitting()) {
NS_WARNING("Commands sent after quit command issued!");
return NS_ERROR_UNEXPECTED;
}
return mXPCShell->EvaluateString(aCommand, aResponse) ?
NS_OK :
NS_ERROR_FAILURE;
nsString response;
if (!mXPCShell->EvaluateString(aCommand, &response)) {
return NS_ERROR_FAILURE;
}
nsresult rv = SendTestShellCommandDestructor(aActor, response);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

Просмотреть файл

@ -38,6 +38,7 @@
#define _IPC_TESTSHELL_TESTSHELLCHILD_H_
#include "mozilla/ipc/TestShellProtocolChild.h"
#include "mozilla/ipc/TestShellCommandProtocolChild.h"
namespace mozilla {
namespace ipc {
@ -48,11 +49,21 @@ class TestShellChild : public TestShellProtocolChild
{
public:
TestShellChild();
virtual ~TestShellChild();
~TestShellChild();
virtual nsresult RecvSendCommand(const nsString& aCommand);
virtual nsresult RecvSendCommandWithResponse(const nsString& aCommand,
nsString* aResponse);
nsresult
RecvExecuteCommand(const nsString& aCommand);
TestShellCommandProtocolChild*
TestShellCommandConstructor(const nsString& aCommand);
nsresult
RecvTestShellCommandConstructor(TestShellCommandProtocolChild* aActor,
const nsString& aCommand);
nsresult
TestShellCommandDestructor(TestShellCommandProtocolChild* aCommand,
const nsString& aResponse);
void SetXPCShell(XPCShellEnvironment* aXPCShell) {
mXPCShell = aXPCShell;

Просмотреть файл

@ -0,0 +1,49 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla IPCShell.
*
* The Initial Developer of the Original Code is
* Ben Turner <bent.mozilla@gmail.com>.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
include protocol "TestShell.ipdl";
namespace mozilla {
namespace ipc {
protocol TestShellCommand
{
manager TestShell;
};
} // namespace ipc
} // namespace mozilla

Просмотреть файл

@ -36,14 +36,96 @@
#include "TestShellParent.h"
#include "nsAutoPtr.h"
#include "XPCShellEnvironment.h"
using mozilla::ipc::TestShellParent;
using mozilla::ipc::TestShellCommandParent;
using mozilla::ipc::TestShellCommandProtocolParent;
using mozilla::ipc::XPCShellEnvironment;
TestShellParent::TestShellParent()
TestShellCommandProtocolParent*
TestShellParent::TestShellCommandConstructor(const nsString& aCommand)
{
return new TestShellCommandParent();
}
TestShellParent::~TestShellParent()
nsresult
TestShellParent::TestShellCommandDestructor(TestShellCommandProtocolParent* aActor,
const nsString& aResponse)
{
NS_ENSURE_ARG_POINTER(aActor);
delete aActor;
return NS_OK;
}
nsresult
TestShellParent::RecvTestShellCommandDestructor(TestShellCommandProtocolParent* aActor,
const nsString& aResponse)
{
NS_ENSURE_ARG_POINTER(aActor);
TestShellCommandParent* command =
static_cast<TestShellCommandParent*>(aActor);
JSBool ok = command->RunCallback(aResponse);
command->ReleaseCallback();
if (!mXPCShell) {
NS_WARNING("Processing a child message after exiting, need to spin events "
"somehow to process this result");
return NS_ERROR_UNEXPECTED;
}
NS_WARN_IF_FALSE(mXPCShell->EventLoopDepth(), "EventLoopDepth mismatch!");
if (mXPCShell->EventLoopDepth()) {
mXPCShell->DecrementEventLoopDepth();
}
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
return NS_OK;
}
JSBool
TestShellCommandParent::SetCallback(JSContext* aCx,
jsval aCallback)
{
if (!mCallback.Hold(aCx)) {
return JS_FALSE;
}
mCallback = aCallback;
mCx = aCx;
return JS_TRUE;
}
JSBool
TestShellCommandParent::RunCallback(const nsString& aResponse)
{
NS_ENSURE_TRUE(mCallback && mCx, JS_FALSE);
JSAutoRequest ar(mCx);
JSObject* global = JS_GetGlobalObject(mCx);
NS_ENSURE_TRUE(global, JS_FALSE);
JSString* str = JS_NewUCStringCopyN(mCx, aResponse.get(), aResponse.Length());
NS_ENSURE_TRUE(str, JS_FALSE);
jsval argv[] = { STRING_TO_JSVAL(str) };
int argc = NS_ARRAY_LENGTH(argv);
jsval rval;
JSBool ok = JS_CallFunctionValue(mCx, global, mCallback, argc, argv, &rval);
NS_ENSURE_TRUE(ok, JS_FALSE);
return JS_TRUE;
}
void
TestShellCommandParent::ReleaseCallback()
{
mCallback.Release();
}

Просмотреть файл

@ -38,15 +38,57 @@
#define _IPC_TESTSHELL_TESTSHELLPARENT_H_
#include "mozilla/ipc/TestShellProtocolParent.h"
#include "mozilla/ipc/TestShellCommandProtocolParent.h"
#include "jsapi.h"
#include "nsAutoJSValHolder.h"
#include "nsStringGlue.h"
namespace mozilla {
namespace ipc {
class XPCShellEnvironment;
class TestShellCommandParent : public TestShellCommandProtocolParent
{
public:
TestShellCommandParent() : mCx(NULL) { }
JSBool SetCallback(JSContext* aCx,
jsval aCallback);
JSBool RunCallback(const nsString& aResponse);
void ReleaseCallback();
private:
JSContext* mCx;
nsAutoJSValHolder mCallback;
};
class TestShellParent : public TestShellProtocolParent
{
public:
TestShellParent();
~TestShellParent();
TestShellParent() : mXPCShell(nsnull) { }
void
SetXPCShell(XPCShellEnvironment* aXPCShell) {
mXPCShell = aXPCShell;
}
TestShellCommandProtocolParent*
TestShellCommandConstructor(const nsString& aCommand);
nsresult
TestShellCommandDestructor(TestShellCommandProtocolParent* aActor,
const nsString& aResponse);
nsresult
RecvTestShellCommandDestructor(TestShellCommandProtocolParent* aActor,
const nsString& aResponse);
private:
XPCShellEnvironment* mXPCShell;
};
} /* namespace ipc */

Просмотреть файл

@ -64,6 +64,7 @@
#include "nsIXPCScriptable.h"
#include "nsJSUtils.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
#include "TestShellChild.h"
@ -75,10 +76,11 @@
using mozilla::ipc::XPCShellEnvironment;
using mozilla::ipc::TestShellChild;
using mozilla::ipc::TestShellParent;
using mozilla::ipc::TestShellCommandProtocolParent;
namespace {
static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
static const char kDefaultRuntimeScriptFilename[] = "ipcshell.js";
class FullTrustSecMan : public nsIScriptSecurityManager
{
@ -774,6 +776,7 @@ ProcessFile(JSContext *cx,
JSBool forceTTY)
{
XPCShellEnvironment* env = Environment(cx);
XPCShellEnvironment::AutoContextPusher pusher(env);
JSScript *script;
jsval result;
@ -875,6 +878,86 @@ ProcessFile(JSContext *cx,
fprintf(stdout, "\n");
}
static JSBool
SendCommand(JSContext *cx,
JSObject *obj,
uintN argc,
jsval *argv,
jsval *rval)
{
if (argc == 0) {
JS_ReportError(cx, "Function takes at least one argument!");
return JS_FALSE;
}
JSString* str = JS_ValueToString(cx, argv[0]);
if (!str) {
JS_ReportError(cx, "Could not convert argument 1 to string!");
return JS_FALSE;
}
nsDependentJSString command(str);
JSBool ok;
if (argc > 1) {
if (JS_TypeOfValue(cx, argv[1]) != JSTYPE_FUNCTION) {
JS_ReportError(cx, "Could not convert argument 2 to function!");
return JS_FALSE;
}
ok = Environment(cx)->DoSendCommand(command, cx, argv[1]);
if (ok) {
Environment(cx)->IncrementEventLoopDepth();
}
}
else {
ok = Environment(cx)->DoSendCommand(command);
}
if (!ok) {
JS_ReportError(cx, "Failed to send command!");
return JS_FALSE;
}
return JS_TRUE;
}
static JSBool
RunEventLoop(JSContext *cx,
JSObject *obj,
uintN argc,
jsval *argv,
jsval *rval)
{
NS_ASSERTION(Environment(cx)->EventLoopDepth() >= 0, "Bad depth!");
Environment(cx)->IncrementEventLoopDepth();
return JS_TRUE;
}
static JSBool
StopEventLoop(JSContext *cx,
JSObject *obj,
uintN argc,
jsval *argv,
jsval *rval)
{
XPCShellEnvironment* env = Environment(cx);
if (env->EventLoopDepth() < 1) {
JS_ReportError(cx, "Mismatched call to DecrementEventLoopDepth");
return JS_FALSE;
}
env->DecrementEventLoopDepth();
return JS_TRUE;
}
JSFunctionSpec gParentFunctions[] =
{
{"sendCommand", SendCommand, 1, 0, 0},
{"runEventLoop", RunEventLoop, 0, 0, 0},
{"stopEventLoop", StopEventLoop, 0, 0, 0},
{nsnull, nsnull, 0, 0, 0}
};
} /* anonymous namespace */
NS_INTERFACE_MAP_BEGIN(FullTrustSecMan)
@ -1179,6 +1262,26 @@ XPCShellDirProvider::GetFile(const char *prop,
return NS_ERROR_FAILURE;
}
XPCShellEnvironment::
AutoContextPusher::AutoContextPusher(XPCShellEnvironment* aEnv)
{
NS_ASSERTION(aEnv->mCx, "Null context?!");
if (NS_SUCCEEDED(aEnv->mCxStack->Push(aEnv->mCx))) {
mEnv = aEnv;
}
}
XPCShellEnvironment::
AutoContextPusher::~AutoContextPusher()
{
if (mEnv) {
JSContext* cx;
mEnv->mCxStack->Pop(&cx);
NS_ASSERTION(cx == mEnv->mCx, "Wrong context on the stack!");
}
}
// static
XPCShellEnvironment*
XPCShellEnvironment::CreateEnvironment()
@ -1202,6 +1305,7 @@ XPCShellEnvironment::XPCShellEnvironment()
: mCx(NULL),
mJSPrincipals(NULL),
mExitCode(0),
mEventLoopDepth(0),
mQuitting(JS_FALSE),
mReportWarnings(JS_TRUE),
mCompileOnly(JS_FALSE),
@ -1222,13 +1326,7 @@ XPCShellEnvironment::~XPCShellEnvironment()
JS_GC(mCx);
if (mCxStack) {
JSContext *oldCx;
mCxStack->Pop(&oldCx);
NS_ASSERTION(oldCx == mCx, "JS thread context push/pop mismatch");
JS_GC(mCx);
}
mCxStack = nsnull;
if (mJSPrincipals) {
JSPRINCIPALS_DROP(mCx, mJSPrincipals);
@ -1326,13 +1424,10 @@ XPCShellEnvironment::Init()
NS_ERROR("failed to get the nsThreadJSContextStack service!");
return false;
}
if(NS_FAILED(cxStack->Push(cx))) {
NS_ERROR("failed to push the current JSContext on the nsThreadJSContextStack!");
return false;
}
mCxStack = cxStack;
AutoContextPusher pusher(this);
nsCOMPtr<nsIXPCScriptable> backstagePass;
rv = rtsvc->GetBackstagePass(getter_AddRefs(backstagePass));
if (NS_FAILED(rv)) {
@ -1392,13 +1487,12 @@ XPCShellEnvironment::Init()
}
void
XPCShellEnvironment::Process(const char* aFilename,
JSBool aIsInteractive)
XPCShellEnvironment::Process(const char* aFilename)
{
NS_ASSERTION(GetGlobalObject(), "Should never be null!");
FILE* file;
if (!aFilename || aIsInteractive) {
if (!aFilename) {
file = stdin;
} else {
file = fopen(aFilename, "r");
@ -1411,77 +1505,21 @@ XPCShellEnvironment::Process(const char* aFilename,
}
}
ProcessFile(mCx, GetGlobalObject(), aFilename, file, aIsInteractive);
if (file != stdin)
ProcessFile(mCx, GetGlobalObject(), aFilename, file, !aFilename);
if (file != stdin) {
fclose(file);
}
if (EventLoopDepth()) {
nsCOMPtr<nsIThread> currentThread;
NS_GetCurrentThread(getter_AddRefs(currentThread));
while (EventLoopDepth()) {
NS_ProcessNextEvent(currentThread, PR_TRUE);
}
}
}
namespace {
static JSBool
SendCommand(JSContext *cx,
JSObject *obj,
uintN argc,
jsval *argv,
jsval *rval)
{
if (argc != 1) {
JS_ReportError(cx, "Function takes only one argument!");
return JS_FALSE;
}
JSString* str = JS_ValueToString(cx, argv[0]);
if (!str) {
JS_ReportError(cx, "Could not convert argument to string!");
return JS_FALSE;
}
nsDependentJSString command(str);
if (!Environment(cx)->DoSendCommand(command)) {
JS_ReportError(cx, "Failed to send command!");
return JS_FALSE;
}
return JS_TRUE;
}
static JSBool
SendCommandWithResponse(JSContext *cx,
JSObject *obj,
uintN argc,
jsval *argv,
jsval *rval)
{
if (argc != 1) {
JS_ReportError(cx, "Function takes only one argument!");
return JS_FALSE;
}
JSString* str = JS_ValueToString(cx, argv[0]);
if (!str) {
JS_ReportError(cx, "Could not convert argument to string!");
return JS_FALSE;
}
nsDependentJSString command(str);
nsAutoString result;
if (!Environment(cx)->DoSendCommand(command, &result)) {
JS_ReportError(cx, "Failed to send command!");
return JS_FALSE;
}
JSString* resultStr = JS_NewUCStringCopyN(cx, result.get(), result.Length());
if (!resultStr) {
JS_ReportError(cx, "Failed to convert response to string!");
return JS_FALSE;
}
*rval = STRING_TO_JSVAL(resultStr);
return JS_TRUE;
}
} /* anonymous namespace */
bool
XPCShellEnvironment::DefineIPCCommands(TestShellChild* aChild)
{
@ -1502,18 +1540,9 @@ XPCShellEnvironment::DefineIPCCommands(TestShellParent* aParent)
JSAutoRequest ar(mCx);
JSFunction* fun = JS_DefineFunction(mCx, global, "sendCommand",
SendCommand, 1, JSPROP_ENUMERATE);
if (!fun) {
NS_WARNING("Failed to define sendCommand function!");
return false;
}
fun = JS_DefineFunction(mCx, global, "sendCommandWithResponse",
SendCommandWithResponse, 1, JSPROP_ENUMERATE);
if (!fun) {
NS_WARNING("Failed to define sendCommandWithResponse function!");
return false;
if (!JS_DefineFunctions(mCx, global, gParentFunctions)) {
NS_ERROR("JS_DefineFunctions failed!");
return false;
}
return true;
@ -1521,13 +1550,25 @@ XPCShellEnvironment::DefineIPCCommands(TestShellParent* aParent)
JSBool
XPCShellEnvironment::DoSendCommand(const nsString& aCommand,
nsString* aResult)
JSContext* aCx,
jsval aCallback)
{
nsresult rv = aResult ?
mParent->SendSendCommandWithResponse(aCommand, aResult) :
mParent->SendSendCommand(aCommand);
if (aCx) {
TestShellCommandParent* command = static_cast<TestShellCommandParent*>(
mParent->SendTestShellCommandConstructor(aCommand));
NS_ENSURE_TRUE(command, JS_FALSE);
return NS_SUCCEEDED(rv) ? JS_TRUE : JS_FALSE;
if (!command->SetCallback(aCx, aCallback)) {
NS_WARNING("Failed to set callback!");
return JS_FALSE;
}
}
else {
nsresult rv = mParent->SendExecuteCommand(aCommand);
NS_ENSURE_SUCCESS(rv, JS_FALSE);
}
return JS_TRUE;
}
bool

Просмотреть файл

@ -65,14 +65,14 @@ public:
static XPCShellEnvironment* CreateEnvironment();
static void DestroyEnvironment(XPCShellEnvironment* aEnv);
void Process(const char* aFilename = nsnull,
JSBool aIsInteractive = JS_FALSE);
void Process(const char* aFilename = nsnull);
bool DefineIPCCommands(TestShellChild* aChild);
bool DefineIPCCommands(TestShellParent* aParent);
JSBool DoSendCommand(const nsString& aCommand,
nsString* aResult = nsnull);
JSContext* aCx = nsnull,
jsval aCallback = JSVAL_VOID);
bool EvaluateString(const nsString& aString,
nsString* aResult = nsnull);
@ -113,6 +113,25 @@ public:
return mCompileOnly;
}
int EventLoopDepth() {
return mEventLoopDepth;
}
void IncrementEventLoopDepth() {
++mEventLoopDepth;
}
void DecrementEventLoopDepth() {
--mEventLoopDepth;
}
class AutoContextPusher
{
public:
AutoContextPusher(XPCShellEnvironment* aEnv);
~AutoContextPusher();
private:
XPCShellEnvironment* mEnv;
};
protected:
XPCShellEnvironment();
~XPCShellEnvironment();
@ -126,6 +145,7 @@ private:
JSPrincipals* mJSPrincipals;
int mExitCode;
int mEventLoopDepth;
JSBool mQuitting;
JSBool mReportWarnings;
JSBool mCompileOnly;

Просмотреть файл

@ -1,3 +1,4 @@
IPDLSRCS = \
TestShell.ipdl \
TestShellCommand.ipdl \
$(NULL)

Просмотреть файл

@ -337,8 +337,8 @@ XRE_InitParentProcess(int aArgc,
base::AtExitManager exitManager;
CommandLine::Init(aArgc, aArgv);
ScopedXREEmbed embed;
MessageLoopForUI mainMessageLoop;
ScopedXREEmbed embed;
{
// Make chromium's IPC thread
@ -422,16 +422,21 @@ TestShellMain(int argc, char** argv)
NS_ENSURE_TRUE(env, 1);
ContentProcessParent* childProcess = ContentProcessParent::GetSingleton();
if (!childProcess)
return 1;
NS_ENSURE_TRUE(childProcess, 1);
TestShellParent* testShellParent = childProcess->CreateTestShell();
NS_ENSURE_TRUE(testShellParent, 1);
env->DefineIPCCommands(testShellParent);
testShellParent->SetXPCShell(env);
bool ok = env->DefineIPCCommands(testShellParent);
NS_ENSURE_TRUE(ok, 1);
const char* filename = argc > 1 ? argv[1] : nsnull;
env->Process(filename);
testShellParent->SetXPCShell(nsnull);
return env->ExitCode();
}