author Mark Banner <standard8@mozilla.com>
Fri, 29 Jul 2016 18:14:48 +0100
changeset 307376 9346c1a86c6c5f09817f60eb600543bcac65ce94
parent 302581 28f7e0062d7fe8374825270dc8c6820f114af06a
child 308059 b214bedbeab67525c7c4526318808d46d400e47e
permissions -rw-r--r--
Backed out changeset 1a8114aa64c1 (bug 1287827) for breaking tests

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "base/file_path.h"
#include "base/process_util.h"
#include "base/waitable_event.h"
#include "chrome/common/child_process_host.h"

#include "mozilla/DebugOnly.h"
#include "mozilla/ipc/FileDescriptor.h"
#include "mozilla/Monitor.h"
#include "mozilla/StaticPtr.h"

#include "nsCOMPtr.h"
#include "nsXULAppAPI.h"        // for GeckoProcessType
#include "nsString.h"

#if defined(XP_WIN) && defined(MOZ_SANDBOX)
#include "sandboxBroker.h"

namespace mozilla {
namespace ipc {

class GeckoChildProcessHost : public ChildProcessHost
  typedef mozilla::Monitor Monitor;
  typedef std::vector<std::string> StringVector;

  typedef base::ChildPrivileges ChildPrivileges;
  typedef base::ProcessHandle ProcessHandle;

  static ChildPrivileges DefaultChildPrivileges();

  explicit GeckoChildProcessHost(GeckoProcessType aProcessType,
                                 ChildPrivileges aPrivileges=base::PRIVILEGES_DEFAULT);


  static nsresult GetArchitecturesForBinary(const char *path, uint32_t *result);

  static uint32_t GetSupportedArchitecturesForProcessType(GeckoProcessType type);

  static uint32_t GetUniqueID();

  // Block until the IPC channel for our subprocess is initialized,
  // but no longer.  The child process may or may not have been
  // created when this method returns.
  bool AsyncLaunch(StringVector aExtraOpts=StringVector(),
                   base::ProcessArchitecture arch=base::GetCurrentProcessArchitecture());

  virtual bool WaitUntilConnected(int32_t aTimeoutMs = 0);

  // Block until the IPC channel for our subprocess is initialized and
  // the OS process is created.  The subprocess may or may not have
  // connected back to us when this method returns.
  // NB: on POSIX, this method is relatively cheap, and doesn't
  // require disk IO.  On win32 however, it requires at least the
  // analogue of stat().  This difference induces a semantic
  // difference in this method: on POSIX, when we return, we know the
  // subprocess has been created, but we don't know whether its
  // executable image can be loaded.  On win32, we do know that when
  // we return.  But we don't know if dynamic linking succeeded on
  // either platform.
  bool LaunchAndWaitForProcessHandle(StringVector aExtraOpts=StringVector());

  // Block until the child process has been created and it connects to
  // the IPC channel, meaning it's fully initialized.  (Or until an
  // error occurs.)
  bool SyncLaunch(StringVector aExtraOpts=StringVector(),
                  int32_t timeoutMs=0,
                  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(IPC::Message&& aMsg);
  virtual void OnChannelError();
  virtual void GetQueuedMessages(std::queue<IPC::Message>& queue);

  virtual void InitializeChannel();

  virtual bool CanShutdown() { return true; }

  IPC::Channel* GetChannel() {
    return channelp();

  // Returns a "borrowed" handle to the child process - the handle returned
  // by this function must not be closed by the caller.
  ProcessHandle GetChildProcessHandle() {
    return mChildProcessHandle;

  GeckoProcessType GetProcessType() {
    return mProcessType;

#ifdef XP_MACOSX
  task_t GetChildTask() {
    return mChildTask;

   * Must run on the IO thread.  Cause the OS process to exit and
   * ensure its OS resources are cleaned up.
  void Join();

  // For bug 943174: Skip the EnsureProcessTerminated call in the destructor.
  void SetAlreadyDead();

  static void EnableSameExecutableForContentProc() { sRunSelfAsContentProc = true; }

  GeckoProcessType mProcessType;
  ChildPrivileges mPrivileges;
  Monitor mMonitor;
  FilePath mProcessPath;

  // This value must be accessed while holding mMonitor.
  enum {
    // This object has been constructed, but the OS process has not
    // yet.
    // The IPC channel for our subprocess has been created, but the OS
    // process has still not been created.
    // The OS process has been created, but it hasn't yet connected to
    // our IPC channel.
    // The process is launched and connected to our IPC channel.  All
    // is well.
  } mProcessState;

  static int32_t mChildCounter;

  void PrepareLaunch();

#ifdef XP_WIN
  void InitWindowsGroupID();
  nsString mGroupId;

  SandboxBroker mSandboxBroker;
  std::vector<std::wstring> mAllowedFilesRead;
  std::vector<std::wstring> mAllowedFilesReadWrite;
  std::vector<std::wstring> mAllowedDirectories;
  bool mEnableSandboxLogging;
  int32_t mSandboxLevel;
#endif // XP_WIN

#if defined(OS_POSIX)
  base::file_handle_mapping_vector mFileMap;

  ProcessHandle mChildProcessHandle;
#if defined(OS_MACOSX)
  task_t mChildTask;

  void OpenPrivilegedHandle(base::ProcessId aPid);


  // Does the actual work for AsyncLaunch, on the IO thread.
  bool PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts,
                                  base::ProcessArchitecture arch);

  bool RunPerformAsyncLaunch(StringVector aExtraOpts=StringVector(),
                             base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture());

  static void GetPathToBinary(FilePath& exePath, GeckoProcessType processType);

  // The buffer is passed to preserve its lifetime until we are done
  // with launching the sub-process.
  void SetChildLogName(const char* varName, const char* origLogName,
                       nsACString &buffer);

  // In between launching the subprocess and handing off its IPC
  // channel, there's a small window of time in which *we* might still
  // be the channel listener, and receive messages.  That's bad
  // because we have no idea what to do with those messages.  So queue
  // them here until we hand off the eventual listener.
  // FIXME/cjones: this strongly indicates bad design.  Shame on us.
  std::queue<IPC::Message> mQueue;

  // Remember original env values so we can restore it (there is no other
  // simple way how to change environment of a child process than to modify
  // the current environment).
  nsCString mRestoreOrigNSPRLogName;
  nsCString mRestoreOrigMozLogName;

  static uint32_t sNextUniqueID;

  static bool sRunSelfAsContentProc;

class GeckoExistingProcessHost final : public GeckoChildProcessHost
  GeckoExistingProcessHost(GeckoProcessType aProcessType,
                           base::ProcessHandle aProcess,
                           const FileDescriptor& aFileDescriptor,
                           ChildPrivileges aPrivileges=base::PRIVILEGES_DEFAULT);


  virtual bool PerformAsyncLaunch(StringVector aExtraOpts=StringVector(),
          base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture()) override;

  virtual void InitializeChannel() override;

  base::ProcessHandle mExistingProcessHandle;
  mozilla::ipc::FileDescriptor mExistingFileDescriptor;
#endif /* MOZ_NUWA_PROCESS */

} /* namespace ipc */
} /* namespace mozilla */