From 140b8112822aba72ff43c7c07cc25e8bec467030 Mon Sep 17 00:00:00 2001 From: "Thinker Lee ext:(%2C%20Cervantes%20Yu%20%3Ccyu%40mozilla.com%3E)" Date: Fri, 31 May 2013 21:16:54 +0800 Subject: [PATCH] Bug 771765 - Support template content process, part 2: IPC and glue changes. r=bent Changes include: * Getting/resetting platform thread ID. * Creating an IPC channel with existing file descriptor sent from the template process. * Child process host with existing process forked from the template. --- .../src/base/platform_thread_posix.cc | 4 ++ ipc/chromium/src/base/process_util_posix.cc | 3 + ipc/chromium/src/base/thread.h | 6 ++ .../src/chrome/common/child_process_host.cc | 18 +++++ .../src/chrome/common/child_process_host.h | 8 +++ ipc/chromium/src/chrome/common/ipc_channel.h | 7 +- .../src/chrome/common/ipc_channel_posix.cc | 17 ++++- .../src/chrome/common/ipc_channel_posix.h | 8 ++- ipc/glue/GeckoChildProcessHost.cpp | 72 ++++++++++++++++--- ipc/glue/GeckoChildProcessHost.h | 34 +++++++-- ipc/glue/Transport_posix.cpp | 2 +- 11 files changed, 159 insertions(+), 20 deletions(-) diff --git a/ipc/chromium/src/base/platform_thread_posix.cc b/ipc/chromium/src/base/platform_thread_posix.cc index e853c4ff4f1a..eb13b980ef83 100644 --- a/ipc/chromium/src/base/platform_thread_posix.cc +++ b/ipc/chromium/src/base/platform_thread_posix.cc @@ -49,7 +49,11 @@ PlatformThreadId PlatformThread::CurrentId() { mach_port_deallocate(mach_task_self(), port); return port; #elif defined(OS_LINUX) +#ifdef MOZ_WIDGET_GONK + return (intptr_t) (pthread_self()); +#else return syscall(__NR_gettid); +#endif #elif defined(OS_OPENBSD) || defined(__GLIBC__) return (intptr_t) (pthread_self()); #elif defined(OS_NETBSD) diff --git a/ipc/chromium/src/base/process_util_posix.cc b/ipc/chromium/src/base/process_util_posix.cc index 77959714aaa0..00d4ef51361e 100644 --- a/ipc/chromium/src/base/process_util_posix.cc +++ b/ipc/chromium/src/base/process_util_posix.cc @@ -248,6 +248,9 @@ bool DidProcessCrash(bool* child_exited, ProcessHandle handle) { int status; const int result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); if (result == -1) { + // The dead process originally spawned from Nuwa might be taken as not + // crashed because the above waitpid() call returns -1 and ECHILD. The + // caller shouldn't behave incorrectly because of this false negative. LOG(ERROR) << "waitpid failed pid:" << handle << " errno:" << errno; if (child_exited) *child_exited = false; diff --git a/ipc/chromium/src/base/thread.h b/ipc/chromium/src/base/thread.h index ae1b513fab66..e3c732a44faa 100644 --- a/ipc/chromium/src/base/thread.h +++ b/ipc/chromium/src/base/thread.h @@ -106,6 +106,12 @@ class Thread : PlatformThread::Delegate { // The thread ID. PlatformThreadId thread_id() const { return thread_id_; } + // Reset thread ID as current thread. + PlatformThreadId reset_thread_id() { + thread_id_ = PlatformThread::CurrentId(); + return thread_id_; + } + // Returns true if the thread has been started, and not yet stopped. // When a thread is running, the thread_id_ is non-zero. bool IsRunning() const { return thread_id_ != 0; } diff --git a/ipc/chromium/src/chrome/common/child_process_host.cc b/ipc/chromium/src/chrome/common/child_process_host.cc index 87947ca85e88..3d590e5a2f87 100644 --- a/ipc/chromium/src/chrome/common/child_process_host.cc +++ b/ipc/chromium/src/chrome/common/child_process_host.cc @@ -12,6 +12,7 @@ #include "base/waitable_event.h" #include "mozilla/ipc/ProcessChild.h" #include "mozilla/ipc/BrowserProcessSubThread.h" +#include "mozilla/ipc/Transport.h" typedef mozilla::ipc::BrowserProcessSubThread ChromeThread; #include "chrome/common/ipc_logging.h" #include "chrome/common/notification_service.h" @@ -19,6 +20,7 @@ typedef mozilla::ipc::BrowserProcessSubThread ChromeThread; #include "chrome/common/process_watcher.h" #include "chrome/common/result_codes.h" +using mozilla::ipc::FileDescriptor; namespace { typedef std::list ChildProcessList; @@ -84,6 +86,22 @@ bool ChildProcessHost::CreateChannel() { return true; } +bool ChildProcessHost::CreateChannel(FileDescriptor& aFileDescriptor) { + if (channel_.get()) { + channel_->Close(); + } + channel_.reset(mozilla::ipc::OpenDescriptor( + aFileDescriptor, IPC::Channel::MODE_SERVER)); + channel_->set_listener(&listener_); + if (!channel_->Connect()) { + return false; + } + + opening_channel_ = true; + + return true; +} + void ChildProcessHost::SetHandle(base::ProcessHandle process) { #if defined(OS_WIN) process_event_.reset(new base::WaitableEvent(process)); diff --git a/ipc/chromium/src/chrome/common/child_process_host.h b/ipc/chromium/src/chrome/common/child_process_host.h index b35e4955ba62..796cdbb2a974 100644 --- a/ipc/chromium/src/chrome/common/child_process_host.h +++ b/ipc/chromium/src/chrome/common/child_process_host.h @@ -15,6 +15,12 @@ #include "chrome/common/child_process_info.h" #include "chrome/common/ipc_channel.h" +namespace mozilla { +namespace ipc { +class FileDescriptor; +} +} + class NotificationType; // Plugins/workers and other child processes that live on the IO thread should @@ -59,6 +65,8 @@ class ChildProcessHost : // Creates the IPC channel. Returns true iff it succeeded. bool CreateChannel(); + bool CreateChannel(mozilla::ipc::FileDescriptor& aFileDescriptor); + // Once the subclass gets a handle to the process, it needs to tell // ChildProcessHost using this function. void SetHandle(base::ProcessHandle handle); diff --git a/ipc/chromium/src/chrome/common/ipc_channel.h b/ipc/chromium/src/chrome/common/ipc_channel.h index 9b2e6a642410..2411cb8a8bfc 100644 --- a/ipc/chromium/src/chrome/common/ipc_channel.h +++ b/ipc/chromium/src/chrome/common/ipc_channel.h @@ -117,8 +117,11 @@ class Channel : public Message::Sender { // socketpair() in which case this method returns -1 for both parameters. void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const; - // Return the server side of the socketpair. - int GetServerFileDescriptor() const; + // Return the file descriptor for communication with the peer. + int GetFileDescriptor() const; + + // Reset the file descriptor for communication with the peer. + void ResetFileDescriptor(int fd); // Close the client side of the socketpair. void CloseClientFileDescriptor(); diff --git a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc index d0f045c1e806..24ba90c5ead2 100644 --- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc +++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc @@ -356,6 +356,15 @@ bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id, return EnqueueHelloMessage(); } +/** + * Reset the file descriptor for communication with the peer. + */ +void Channel::ChannelImpl::ResetFileDescriptor(int fd) { + NS_ASSERTION(fd > 0 && fd == pipe_, "Invalid file descriptor"); + + EnqueueHelloMessage(); +} + bool Channel::ChannelImpl::EnqueueHelloMessage() { scoped_ptr msg(new Message(MSG_ROUTING_NONE, HELLO_MESSAGE_TYPE, @@ -971,8 +980,12 @@ void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const { return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd); } -int Channel::GetServerFileDescriptor() const { - return channel_impl_->GetServerFileDescriptor(); +void Channel::ResetFileDescriptor(int fd) { + channel_impl_->ResetFileDescriptor(fd); +} + +int Channel::GetFileDescriptor() const { + return channel_impl_->GetFileDescriptor(); } void Channel::CloseClientFileDescriptor() { diff --git a/ipc/chromium/src/chrome/common/ipc_channel_posix.h b/ipc/chromium/src/chrome/common/ipc_channel_posix.h index d8d413923196..12d56ad4b798 100644 --- a/ipc/chromium/src/chrome/common/ipc_channel_posix.h +++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.h @@ -36,9 +36,11 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher { } bool Send(Message* message); void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const; - int GetServerFileDescriptor() const { - DCHECK(mode_ == MODE_SERVER); - return pipe_; + + void ResetFileDescriptor(int fd); + + int GetFileDescriptor() const { + return pipe_; } void CloseClientFileDescriptor(); diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index cc639771cc10..573e94339873 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -34,6 +34,10 @@ #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1" #endif +#include "nsTArray.h" +#include "nsClassHashtable.h" +#include "nsHashKeys.h" + using mozilla::MonitorAutoLock; using mozilla::ipc::GeckoChildProcessHost; @@ -89,11 +93,6 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType, #endif { MOZ_COUNT_CTOR(GeckoChildProcessHost); - - MessageLoop* ioLoop = XRE_GetIOMessageLoop(); - ioLoop->PostTask(FROM_HERE, - NewRunnableMethod(this, - &GeckoChildProcessHost::InitializeChannel)); } GeckoChildProcessHost::~GeckoChildProcessHost() @@ -287,7 +286,7 @@ GeckoChildProcessHost::SyncLaunch(std::vector aExtraOpts, int aTime ioLoop->PostTask(FROM_HERE, NewRunnableMethod(this, - &GeckoChildProcessHost::PerformAsyncLaunch, + &GeckoChildProcessHost::RunPerformAsyncLaunch, aExtraOpts, arch)); // NB: this uses a different mechanism than the chromium parent // class. @@ -322,7 +321,7 @@ GeckoChildProcessHost::AsyncLaunch(std::vector aExtraOpts) MessageLoop* ioLoop = XRE_GetIOMessageLoop(); ioLoop->PostTask(FROM_HERE, NewRunnableMethod(this, - &GeckoChildProcessHost::PerformAsyncLaunch, + &GeckoChildProcessHost::RunPerformAsyncLaunch, aExtraOpts, base::GetCurrentProcessArchitecture())); // This may look like the sync launch wait, but we only delay as @@ -343,7 +342,7 @@ GeckoChildProcessHost::LaunchAndWaitForProcessHandle(StringVector aExtraOpts) MessageLoop* ioLoop = XRE_GetIOMessageLoop(); ioLoop->PostTask(FROM_HERE, NewRunnableMethod(this, - &GeckoChildProcessHost::PerformAsyncLaunch, + &GeckoChildProcessHost::RunPerformAsyncLaunch, aExtraOpts, base::GetCurrentProcessArchitecture())); MonitorAutoLock lock(mMonitor); @@ -425,6 +424,14 @@ GeckoChildProcessHost::PerformAsyncLaunch(std::vector aExtraOpts, b return retval; } +bool +GeckoChildProcessHost::RunPerformAsyncLaunch(std::vector aExtraOpts, + base::ProcessArchitecture aArch) +{ + InitializeChannel(); + return PerformAsyncLaunch(aExtraOpts, aArch); +} + void #if defined(XP_WIN) AddAppDirToCommandLine(CommandLine& aCmdLine) @@ -833,3 +840,52 @@ GeckoChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event) } ChildProcessHost::OnWaitableEventSignaled(event); } + +#ifdef MOZ_NUWA_PROCESS + +using mozilla::ipc::GeckoExistingProcessHost; +using mozilla::ipc::FileDescriptor; + +GeckoExistingProcessHost:: +GeckoExistingProcessHost(GeckoProcessType aProcessType, + base::ProcessHandle aProcess, + const FileDescriptor& aFileDescriptor, + ChildPrivileges aPrivileges) + : GeckoChildProcessHost(aProcessType, aPrivileges) + , mExistingProcessHandle(aProcess) + , mExistingFileDescriptor(aFileDescriptor) +{ + NS_ASSERTION(aFileDescriptor.IsValid(), + "Expected file descriptor to be valid"); +} + +GeckoExistingProcessHost::~GeckoExistingProcessHost() +{ +} + +bool +GeckoExistingProcessHost::PerformAsyncLaunch(StringVector aExtraOpts, + base::ProcessArchitecture aArch) +{ + SetHandle(mExistingProcessHandle); + + OpenPrivilegedHandle(base::GetProcId(mExistingProcessHandle)); + + MonitorAutoLock lock(mMonitor); + mProcessState = PROCESS_CREATED; + lock.Notify(); + + return true; +} + +void +GeckoExistingProcessHost::InitializeChannel() +{ + CreateChannel(mExistingFileDescriptor); + + MonitorAutoLock lock(mMonitor); + mProcessState = CHANNEL_INITIALIZED; + lock.Notify(); +} + +#endif /* MOZ_NUWA_PROCESS */ diff --git a/ipc/glue/GeckoChildProcessHost.h b/ipc/glue/GeckoChildProcessHost.h index 46c70307aef6..836333d5371f 100644 --- a/ipc/glue/GeckoChildProcessHost.h +++ b/ipc/glue/GeckoChildProcessHost.h @@ -11,6 +11,7 @@ #include "base/waitable_event.h" #include "chrome/common/child_process_host.h" +#include "mozilla/ipc/FileDescriptor.h" #include "mozilla/Monitor.h" #include "nsXULAppAPI.h" // for GeckoProcessType @@ -66,15 +67,15 @@ public: int32_t timeoutMs=0, base::ProcessArchitecture arch=base::GetCurrentProcessArchitecture()); - bool PerformAsyncLaunch(StringVector aExtraOpts=StringVector(), - base::ProcessArchitecture arch=base::GetCurrentProcessArchitecture()); + virtual bool PerformAsyncLaunch(StringVector aExtraOpts=StringVector(), + base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture()); virtual void OnChannelConnected(int32_t peer_pid); virtual void OnMessageReceived(const IPC::Message& aMsg); virtual void OnChannelError(); virtual void GetQueuedMessages(std::queue& queue); - void InitializeChannel(); + virtual void InitializeChannel(); virtual bool CanShutdown() { return true; } @@ -146,6 +147,8 @@ protected: task_t mChildTask; #endif + void OpenPrivilegedHandle(base::ProcessId aPid); + private: DISALLOW_EVIL_CONSTRUCTORS(GeckoChildProcessHost); @@ -153,7 +156,8 @@ private: bool PerformAsyncLaunchInternal(std::vector& aExtraOpts, base::ProcessArchitecture arch); - void OpenPrivilegedHandle(base::ProcessId aPid); + bool RunPerformAsyncLaunch(StringVector aExtraOpts=StringVector(), + base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture()); // In between launching the subprocess and handing off its IPC // channel, there's a small window of time in which *we* might still @@ -165,6 +169,28 @@ private: std::queue mQueue; }; +#ifdef MOZ_NUWA_PROCESS +class GeckoExistingProcessHost MOZ_FINAL : public GeckoChildProcessHost +{ +public: + GeckoExistingProcessHost(GeckoProcessType aProcessType, + base::ProcessHandle aProcess, + const FileDescriptor& aFileDescriptor, + ChildPrivileges aPrivileges=base::PRIVILEGES_DEFAULT); + + ~GeckoExistingProcessHost(); + + virtual bool PerformAsyncLaunch(StringVector aExtraOpts=StringVector(), + base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture()) MOZ_OVERRIDE; + + virtual void InitializeChannel() MOZ_OVERRIDE; + +private: + base::ProcessHandle mExistingProcessHandle; + mozilla::ipc::FileDescriptor mExistingFileDescriptor; +}; +#endif /* MOZ_NUWA_PROCESS */ + } /* namespace ipc */ } /* namespace mozilla */ diff --git a/ipc/glue/Transport_posix.cpp b/ipc/glue/Transport_posix.cpp index a9e53c5e8fc6..7ab47eb9f32a 100644 --- a/ipc/glue/Transport_posix.cpp +++ b/ipc/glue/Transport_posix.cpp @@ -29,7 +29,7 @@ CreateTransport(ProcessHandle /*unused*/, ProcessHandle /*unused*/, wstring id = ChildProcessInfo::GenerateRandomChannelID(aOne); // Use MODE_SERVER to force creation of the socketpair Transport t(id, Transport::MODE_SERVER, nullptr); - int fd1 = t.GetServerFileDescriptor(); + int fd1 = t.GetFileDescriptor(); int fd2, dontcare; t.GetClientFileDescriptorMapping(&fd2, &dontcare); if (fd1 < 0 || fd2 < 0) {