Bug 592768 - When using async launch, the toplevel actor doesn't have a process handle. Set the process ID with a callback function (OnChannelConnected). r=cjones
authorBenedict Hsieh <ben.hsieh@gmail.com>
Fri, 08 Oct 2010 16:24:36 -0700
changeset 57663 a450d42197b2b2c093590ffb4e4a8982645ca45a
parent 57662 dc021bc9929f6a93abc1aac7867600d90c3ba2cc
child 57664 238d99ca6886dccc32a6599184c5dc855ed55254
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewerscjones
bugs592768
milestone2.0b8pre
Bug 592768 - When using async launch, the toplevel actor doesn't have a process handle. Set the process ID with a callback function (OnChannelConnected). r=cjones
ipc/glue/AsyncChannel.cpp
ipc/glue/AsyncChannel.h
ipc/glue/RPCChannel.h
ipc/glue/SyncChannel.h
ipc/ipdl/ipdl/lower.py
js/jetpack/JetpackParent.cpp
js/jetpack/JetpackParent.h
--- a/ipc/glue/AsyncChannel.cpp
+++ b/ipc/glue/AsyncChannel.cpp
@@ -460,28 +460,40 @@ void
 AsyncChannel::OnChannelOpened()
 {
     AssertIOThread();
     mChannelState = ChannelOpening;
     /*assert*/mTransport->Connect();
 }
 
 void
+AsyncChannel::DispatchOnChannelConnected(int32 peer_pid)
+{
+    AssertWorkerThread();
+    if (mListener)
+        mListener->OnChannelConnected(peer_pid);
+}
+
+void
 AsyncChannel::OnChannelConnected(int32 peer_pid)
 {
     AssertIOThread();
 
     {
         MutexAutoLock lock(mMutex);
         mChannelState = ChannelConnected;
         mCvar.Notify();
     }
 
     if(mExistingListener)
         mExistingListener->OnChannelConnected(peer_pid);
+
+    mWorkerLoop->PostTask(FROM_HERE, NewRunnableMethod(this, 
+                                                       &AsyncChannel::DispatchOnChannelConnected, 
+                                                       peer_pid));
 }
 
 void
 AsyncChannel::OnChannelError()
 {
     AssertIOThread();
 
     MutexAutoLock lock(mMutex);
--- a/ipc/glue/AsyncChannel.h
+++ b/ipc/glue/AsyncChannel.h
@@ -90,16 +90,17 @@ public:
     {
     public:
         virtual ~AsyncListener() { }
 
         virtual void OnChannelClose() = 0;
         virtual void OnChannelError() = 0;
         virtual Result OnMessageReceived(const Message& aMessage) = 0;
         virtual void OnProcessingError(Result aError) = 0;
+        virtual void OnChannelConnected(int32 peer_pid) {};
     };
 
 public:
     //
     // These methods are called on the "worker" thread
     //
     AsyncChannel(AsyncListener* aListener);
     virtual ~AsyncChannel();
@@ -112,16 +113,19 @@ public:
     bool Open(Transport* aTransport, MessageLoop* aIOLoop=0);
     
     // Close the underlying transport channel.
     void Close();
 
     // Asynchronously send a message to the other side of the channel
     virtual bool Send(Message* msg);
 
+    // Send OnChannelConnected notification to listeners.
+    void DispatchOnChannelConnected(int32 peer_pid);
+
     //
     // These methods are called on the "IO" thread
     //
 
     // Implement the IPC::Channel::Listener interface
     NS_OVERRIDE virtual void OnMessageReceived(const Message& msg);
     NS_OVERRIDE virtual void OnChannelConnected(int32 peer_pid);
     NS_OVERRIDE virtual void OnChannelError();
--- a/ipc/glue/RPCChannel.h
+++ b/ipc/glue/RPCChannel.h
@@ -79,16 +79,17 @@ public:
         virtual void OnChannelError() = 0;
         virtual Result OnMessageReceived(const Message& aMessage) = 0;
         virtual void OnProcessingError(Result aError) = 0;
         virtual bool OnReplyTimeout() = 0;
         virtual Result OnMessageReceived(const Message& aMessage,
                                          Message*& aReply) = 0;
         virtual Result OnCallReceived(const Message& aMessage,
                                       Message*& aReply) = 0;
+        virtual void OnChannelConnected(int32 peer_pid) {};
 
         virtual void OnEnteredCxxStack()
         {
             NS_RUNTIMEABORT("default impl shouldn't be invoked");
         }
 
         virtual void OnExitedCxxStack()
         {
--- a/ipc/glue/SyncChannel.h
+++ b/ipc/glue/SyncChannel.h
@@ -62,16 +62,17 @@ public:
 
         virtual void OnChannelClose() = 0;
         virtual void OnChannelError() = 0;
         virtual Result OnMessageReceived(const Message& aMessage) = 0;
         virtual void OnProcessingError(Result aError) = 0;
         virtual bool OnReplyTimeout() = 0;
         virtual Result OnMessageReceived(const Message& aMessage,
                                          Message*& aReply) = 0;
+        virtual void OnChannelConnected(int32 peer_pid) {};
     };
 
     SyncChannel(SyncListener* aListener);
     virtual ~SyncChannel();
 
     NS_OVERRIDE
     virtual bool Send(Message* msg) {
         return AsyncChannel::Send(msg);
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -2811,16 +2811,23 @@ class _GenerateProtocolActorCode(ipdl.as
                 StmtExpr(ExprCall(deallocsubtreevar)),
                 StmtExpr(ExprCall(deallocshmemvar))
             ])
         else:
             onerror.addstmt(
                 _runtimeAbort("`OnError' called on non-toplevel actor"))
         self.cls.addstmts([ onerror, Whitespace.NL ])
 
+        # OnChannelConnected()
+        onconnected = MethodDefn(MethodDecl('OnChannelConnected'))
+        if not ptype.isToplevel():
+            onconnected.addstmt(
+                _runtimeAbort("'OnConnected' called on non-toplevel actor"))
+
+        self.cls.addstmts([ onconnected, Whitespace.NL ])
         # FIXME/bug 535053: only manager protocols and non-manager
         # protocols with union types need Lookup().  we'll give it to
         # all for the time being (simpler)
         if 1 or ptype.isManager():
             self.cls.addstmts(self.implementManagerIface())
 
         # User-facing shmem methods
         self.cls.addstmts(self.makeShmemIface())
@@ -2839,16 +2846,26 @@ class _GenerateProtocolActorCode(ipdl.as
                     CppDirective('else'),
                     _runtimeAbort('This method is Windows-only'),
                     CppDirective('endif'),
                     ])
 
             self.cls.addstmts([ processnative, Whitespace.NL ])
 
         if ptype.isToplevel() and self.side is 'parent':
+            ## void SetOtherProcess(ProcessHandle pid)
+            otherprocessvar = ExprVar('aOtherProcess')
+            setotherprocess = MethodDefn(MethodDecl(
+                    'SetOtherProcess',
+                    params=[ Decl(Type('ProcessHandle'), otherprocessvar.name)]))
+            setotherprocess.addstmt(StmtExpr(ExprAssn(p.otherProcessVar(), otherprocessvar)))
+            self.cls.addstmts([
+                    setotherprocess,
+                    Whitespace.NL])
+
             ## bool GetMinidump(nsIFile** dump)
             self.cls.addstmt(Label.PROTECTED)
 
             otherpidvar = ExprVar('OtherSidePID')
             otherpid = MethodDefn(MethodDecl(
                 otherpidvar.name, params=[ ],
                 ret=Type('base::ProcessId'),
                 const=1))
--- a/js/jetpack/JetpackParent.cpp
+++ b/js/jetpack/JetpackParent.cpp
@@ -32,16 +32,17 @@
  * 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 "mozilla/jetpack/JetpackParent.h"
 #include "mozilla/jetpack/Handle.h"
+#include "base/process_util.h"
 
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsIVariant.h"
 #include "nsIXPConnect.h"
 #include "nsIJSContextStack.h"
 
 namespace mozilla {
@@ -55,16 +56,19 @@ JetpackParent::JetpackParent(JSContext* 
   Open(mSubprocess->GetChannel(),
        mSubprocess->GetChildProcessHandle());
 }
 
 JetpackParent::~JetpackParent()
 {
   if (mSubprocess)
     Destroy();
+
+  if (OtherProcess())
+    base::CloseProcessHandle(OtherProcess());
 }
 
 NS_IMPL_ISUPPORTS1(JetpackParent, nsIJetpack)
 
 NS_IMETHODIMP
 JetpackParent::SendMessage(const nsAString& aMessageName)
 {
   nsresult rv;
@@ -237,10 +241,20 @@ JetpackParent::AllocPHandle()
 
 bool
 JetpackParent::DeallocPHandle(PHandleParent* actor)
 {
   delete actor;
   return true;
 }
 
+void
+JetpackParent::OnChannelConnected(int32 pid) 
+{
+  ProcessHandle handle;
+  if (!base::OpenPrivilegedProcessHandle(pid, &handle))
+    NS_RUNTIMEABORT("can't open handle to child process");
+
+  SetOtherProcess(handle);
+}
+
 } // namespace jetpack
 } // namespace mozilla
--- a/js/jetpack/JetpackParent.h
+++ b/js/jetpack/JetpackParent.h
@@ -60,16 +60,18 @@ class JetpackParent
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIJETPACK
 
   JetpackParent(JSContext* cx);
   ~JetpackParent();
 
+  void OnChannelConnected(int32 pid);
+
 protected:
   NS_OVERRIDE virtual bool RecvSendMessage(const nsString& messageName,
                                            const InfallibleTArray<Variant>& data);
   NS_OVERRIDE virtual bool AnswerCallMessage(const nsString& messageName,
                                              const InfallibleTArray<Variant>& data,
                                              InfallibleTArray<Variant>* results);
 
   NS_OVERRIDE virtual PHandleParent* AllocPHandle();