mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-05 05:30:29 +00:00
Fix testshell to use the new callback commands, and shut down properly
This commit is contained in:
parent
24b18f8473
commit
9d33531365
@ -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;
|
||||
|
49
ipc/testshell/TestShellCommand.ipdl
Normal file
49
ipc/testshell/TestShellCommand.ipdl
Normal file
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user