michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef __IPC_GLUE_GECKOCHILDPROCESSHOST_H__ michael@0: #define __IPC_GLUE_GECKOCHILDPROCESSHOST_H__ michael@0: michael@0: #include "base/file_path.h" michael@0: #include "base/process_util.h" michael@0: #include "base/scoped_ptr.h" michael@0: #include "base/waitable_event.h" michael@0: #include "chrome/common/child_process_host.h" michael@0: michael@0: #include "mozilla/DebugOnly.h" michael@0: #include "mozilla/ipc/FileDescriptor.h" michael@0: #include "mozilla/Monitor.h" michael@0: #include "mozilla/StaticPtr.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsXULAppAPI.h" // for GeckoProcessType michael@0: #include "nsString.h" michael@0: michael@0: class nsIFile; michael@0: michael@0: namespace mozilla { michael@0: namespace ipc { michael@0: michael@0: class GeckoChildProcessHost : public ChildProcessHost michael@0: { michael@0: protected: michael@0: typedef mozilla::Monitor Monitor; michael@0: typedef std::vector StringVector; michael@0: michael@0: public: michael@0: typedef base::ChildPrivileges ChildPrivileges; michael@0: typedef base::ProcessHandle ProcessHandle; michael@0: michael@0: static ChildPrivileges DefaultChildPrivileges(); michael@0: michael@0: GeckoChildProcessHost(GeckoProcessType aProcessType, michael@0: ChildPrivileges aPrivileges=base::PRIVILEGES_DEFAULT); michael@0: michael@0: ~GeckoChildProcessHost(); michael@0: michael@0: static nsresult GetArchitecturesForBinary(const char *path, uint32_t *result); michael@0: michael@0: static uint32_t GetSupportedArchitecturesForProcessType(GeckoProcessType type); michael@0: michael@0: // Block until the IPC channel for our subprocess is initialized, michael@0: // but no longer. The child process may or may not have been michael@0: // created when this method returns. michael@0: bool AsyncLaunch(StringVector aExtraOpts=StringVector()); michael@0: michael@0: // Block until the IPC channel for our subprocess is initialized and michael@0: // the OS process is created. The subprocess may or may not have michael@0: // connected back to us when this method returns. michael@0: // michael@0: // NB: on POSIX, this method is relatively cheap, and doesn't michael@0: // require disk IO. On win32 however, it requires at least the michael@0: // analogue of stat(). This difference induces a semantic michael@0: // difference in this method: on POSIX, when we return, we know the michael@0: // subprocess has been created, but we don't know whether its michael@0: // executable image can be loaded. On win32, we do know that when michael@0: // we return. But we don't know if dynamic linking succeeded on michael@0: // either platform. michael@0: bool LaunchAndWaitForProcessHandle(StringVector aExtraOpts=StringVector()); michael@0: michael@0: // Block until the child process has been created and it connects to michael@0: // the IPC channel, meaning it's fully initialized. (Or until an michael@0: // error occurs.) michael@0: bool SyncLaunch(StringVector aExtraOpts=StringVector(), michael@0: int32_t timeoutMs=0, michael@0: base::ProcessArchitecture arch=base::GetCurrentProcessArchitecture()); michael@0: michael@0: virtual bool PerformAsyncLaunch(StringVector aExtraOpts=StringVector(), michael@0: base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture()); michael@0: michael@0: virtual void OnChannelConnected(int32_t peer_pid); michael@0: virtual void OnMessageReceived(const IPC::Message& aMsg); michael@0: virtual void OnChannelError(); michael@0: virtual void GetQueuedMessages(std::queue& queue); michael@0: michael@0: virtual void InitializeChannel(); michael@0: michael@0: virtual bool CanShutdown() { return true; } michael@0: michael@0: virtual void OnWaitableEventSignaled(base::WaitableEvent *event); michael@0: michael@0: IPC::Channel* GetChannel() { michael@0: return channelp(); michael@0: } michael@0: michael@0: base::WaitableEvent* GetShutDownEvent() { michael@0: return GetProcessEvent(); michael@0: } michael@0: michael@0: // Returns a "borrowed" handle to the child process - the handle returned michael@0: // by this function must not be closed by the caller. michael@0: ProcessHandle GetChildProcessHandle() { michael@0: return mChildProcessHandle; michael@0: } michael@0: michael@0: // Returns an "owned" handle to the child process - the handle returned michael@0: // by this function must be closed by the caller. michael@0: ProcessHandle GetOwnedChildProcessHandle() { michael@0: ProcessHandle handle; michael@0: // We use OpenPrivilegedProcessHandle as that is where our michael@0: // mChildProcessHandle initially came from. michael@0: bool ok = base::OpenPrivilegedProcessHandle(base::GetProcId(mChildProcessHandle), michael@0: &handle); michael@0: NS_ASSERTION(ok, "Failed to get owned process handle"); michael@0: return ok ? handle : 0; michael@0: } michael@0: michael@0: GeckoProcessType GetProcessType() { michael@0: return mProcessType; michael@0: } michael@0: michael@0: #ifdef XP_MACOSX michael@0: task_t GetChildTask() { michael@0: return mChildTask; michael@0: } michael@0: #endif michael@0: michael@0: /** michael@0: * Must run on the IO thread. Cause the OS process to exit and michael@0: * ensure its OS resources are cleaned up. michael@0: */ michael@0: void Join(); michael@0: michael@0: // For bug 943174: Skip the EnsureProcessTerminated call in the destructor. michael@0: void SetAlreadyDead(); michael@0: michael@0: void SetSandboxEnabled(bool aSandboxEnabled) { michael@0: mSandboxEnabled = aSandboxEnabled; michael@0: } michael@0: michael@0: protected: michael@0: GeckoProcessType mProcessType; michael@0: bool mSandboxEnabled; michael@0: ChildPrivileges mPrivileges; michael@0: Monitor mMonitor; michael@0: FilePath mProcessPath; michael@0: michael@0: // This value must be accessed while holding mMonitor. michael@0: enum { michael@0: // This object has been constructed, but the OS process has not michael@0: // yet. michael@0: CREATING_CHANNEL = 0, michael@0: // The IPC channel for our subprocess has been created, but the OS michael@0: // process has still not been created. michael@0: CHANNEL_INITIALIZED, michael@0: // The OS process has been created, but it hasn't yet connected to michael@0: // our IPC channel. michael@0: PROCESS_CREATED, michael@0: // The process is launched and connected to our IPC channel. All michael@0: // is well. michael@0: PROCESS_CONNECTED, michael@0: PROCESS_ERROR michael@0: } mProcessState; michael@0: michael@0: static int32_t mChildCounter; michael@0: michael@0: void PrepareLaunch(); michael@0: michael@0: #ifdef XP_WIN michael@0: void InitWindowsGroupID(); michael@0: nsString mGroupId; michael@0: #endif michael@0: michael@0: #if defined(OS_POSIX) michael@0: base::file_handle_mapping_vector mFileMap; michael@0: #endif michael@0: michael@0: base::WaitableEventWatcher::Delegate* mDelegate; michael@0: michael@0: ProcessHandle mChildProcessHandle; michael@0: #if defined(OS_MACOSX) michael@0: task_t mChildTask; michael@0: #endif michael@0: michael@0: void OpenPrivilegedHandle(base::ProcessId aPid); michael@0: michael@0: private: michael@0: DISALLOW_EVIL_CONSTRUCTORS(GeckoChildProcessHost); michael@0: michael@0: // Does the actual work for AsyncLaunch, on the IO thread. michael@0: bool PerformAsyncLaunchInternal(std::vector& aExtraOpts, michael@0: base::ProcessArchitecture arch); michael@0: michael@0: bool RunPerformAsyncLaunch(StringVector aExtraOpts=StringVector(), michael@0: base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture()); michael@0: michael@0: static void GetPathToBinary(FilePath& exePath); michael@0: static void CacheGreDir(); michael@0: michael@0: // In between launching the subprocess and handing off its IPC michael@0: // channel, there's a small window of time in which *we* might still michael@0: // be the channel listener, and receive messages. That's bad michael@0: // because we have no idea what to do with those messages. So queue michael@0: // them here until we hand off the eventual listener. michael@0: // michael@0: // FIXME/cjones: this strongly indicates bad design. Shame on us. michael@0: std::queue mQueue; michael@0: michael@0: static StaticRefPtr sGreDir; michael@0: static DebugOnly sGreDirCached; michael@0: }; michael@0: michael@0: #ifdef MOZ_NUWA_PROCESS michael@0: class GeckoExistingProcessHost MOZ_FINAL : public GeckoChildProcessHost michael@0: { michael@0: public: michael@0: GeckoExistingProcessHost(GeckoProcessType aProcessType, michael@0: base::ProcessHandle aProcess, michael@0: const FileDescriptor& aFileDescriptor, michael@0: ChildPrivileges aPrivileges=base::PRIVILEGES_DEFAULT); michael@0: michael@0: ~GeckoExistingProcessHost(); michael@0: michael@0: virtual bool PerformAsyncLaunch(StringVector aExtraOpts=StringVector(), michael@0: base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture()) MOZ_OVERRIDE; michael@0: michael@0: virtual void InitializeChannel() MOZ_OVERRIDE; michael@0: michael@0: private: michael@0: base::ProcessHandle mExistingProcessHandle; michael@0: mozilla::ipc::FileDescriptor mExistingFileDescriptor; michael@0: }; michael@0: #endif /* MOZ_NUWA_PROCESS */ michael@0: michael@0: } /* namespace ipc */ michael@0: } /* namespace mozilla */ michael@0: michael@0: #endif /* __IPC_GLUE_GECKOCHILDPROCESSHOST_H__ */