Home | History | Annotate | Download | only in browser
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CHROME_BROWSER_PROCESS_SINGLETON_H_
      6 #define CHROME_BROWSER_PROCESS_SINGLETON_H_
      7 
      8 #include "build/build_config.h"
      9 
     10 #if defined(OS_WIN)
     11 #include <windows.h>
     12 #endif  // defined(OS_WIN)
     13 
     14 #include <set>
     15 #include <vector>
     16 
     17 #include "base/basictypes.h"
     18 #include "base/callback.h"
     19 #include "base/command_line.h"
     20 #include "base/files/file_path.h"
     21 #include "base/logging.h"
     22 #include "base/memory/ref_counted.h"
     23 #include "base/process/process.h"
     24 #include "base/threading/non_thread_safe.h"
     25 #include "ui/gfx/native_widget_types.h"
     26 
     27 #if defined(OS_LINUX) || defined(OS_OPENBSD)
     28 #include "base/files/scoped_temp_dir.h"
     29 #endif  // defined(OS_LINUX) || defined(OS_OPENBSD)
     30 
     31 #if defined(OS_WIN)
     32 #include "base/win/message_window.h"
     33 #endif  // defined(OS_WIN)
     34 
     35 class CommandLine;
     36 
     37 // ProcessSingleton ----------------------------------------------------------
     38 //
     39 // This class allows different browser processes to communicate with
     40 // each other.  It is named according to the user data directory, so
     41 // we can be sure that no more than one copy of the application can be
     42 // running at once with a given data directory.
     43 //
     44 // Implementation notes:
     45 // - the Windows implementation uses an invisible global message window;
     46 // - the Linux implementation uses a Unix domain socket in the user data dir.
     47 
     48 class ProcessSingleton : public base::NonThreadSafe {
     49  public:
     50   enum NotifyResult {
     51     PROCESS_NONE,
     52     PROCESS_NOTIFIED,
     53     PROFILE_IN_USE,
     54     LOCK_ERROR,
     55     NUM_NOTIFY_RESULTS,
     56   };
     57 
     58   // Implement this callback to handle notifications from other processes. The
     59   // callback will receive the command line and directory with which the other
     60   // Chrome process was launched. Return true if the command line will be
     61   // handled within the current browser instance or false if the remote process
     62   // should handle it (i.e., because the current process is shutting down).
     63   typedef base::Callback<bool(
     64       const CommandLine& command_line,
     65       const base::FilePath& current_directory)> NotificationCallback;
     66 
     67   ProcessSingleton(const base::FilePath& user_data_dir,
     68                    const NotificationCallback& notification_callback);
     69   ~ProcessSingleton();
     70 
     71   // Notify another process, if available. Otherwise sets ourselves as the
     72   // singleton instance. Returns PROCESS_NONE if we became the singleton
     73   // instance. Callers are guaranteed to either have notified an existing
     74   // process or have grabbed the singleton (unless the profile is locked by an
     75   // unreachable process).
     76   // TODO(brettw): Make the implementation of this method non-platform-specific
     77   // by making Linux re-use the Windows implementation.
     78   NotifyResult NotifyOtherProcessOrCreate();
     79 
     80   // Sets ourself up as the singleton instance.  Returns true on success.  If
     81   // false is returned, we are not the singleton instance and the caller must
     82   // exit.
     83   // NOTE: Most callers should generally prefer NotifyOtherProcessOrCreate() to
     84   // this method, only callers for whom failure is prefered to notifying another
     85   // process should call this directly.
     86   bool Create();
     87 
     88   // Clear any lock state during shutdown.
     89   void Cleanup();
     90 
     91 #if defined(OS_LINUX) || defined(OS_OPENBSD)
     92   static void DisablePromptForTesting();
     93 #endif  // defined(OS_LINUX) || defined(OS_OPENBSD)
     94 
     95  protected:
     96   // Notify another process, if available.
     97   // Returns true if another process was found and notified, false if we should
     98   // continue with the current process.
     99   // On Windows, Create() has to be called before this.
    100   NotifyResult NotifyOtherProcess();
    101 
    102 #if defined(OS_LINUX) || defined(OS_OPENBSD)
    103   // Exposed for testing.  We use a timeout on Linux, and in tests we want
    104   // this timeout to be short.
    105   NotifyResult NotifyOtherProcessWithTimeout(const CommandLine& command_line,
    106                                              int timeout_seconds,
    107                                              bool kill_unresponsive);
    108   NotifyResult NotifyOtherProcessWithTimeoutOrCreate(
    109       const CommandLine& command_line,
    110       int timeout_seconds);
    111   void OverrideCurrentPidForTesting(base::ProcessId pid);
    112   void OverrideKillCallbackForTesting(
    113       const base::Callback<void(int)>& callback);
    114 #endif  // defined(OS_LINUX) || defined(OS_OPENBSD)
    115 
    116  private:
    117 #if !defined(OS_MACOSX)
    118   // Timeout for the current browser process to respond. 20 seconds should be
    119   // enough. It's only used in Windows and Linux implementations.
    120   static const int kTimeoutInSeconds = 20;
    121 #endif
    122 
    123   NotificationCallback notification_callback_;  // Handler for notifications.
    124 
    125 #if defined(OS_WIN)
    126   bool EscapeVirtualization(const base::FilePath& user_data_dir);
    127 
    128   HWND remote_window_;  // The HWND_MESSAGE of another browser.
    129   base::win::MessageWindow window_;  // The message-only window.
    130   bool is_virtualized_;  // Stuck inside Microsoft Softricity VM environment.
    131   HANDLE lock_file_;
    132   base::FilePath user_data_dir_;
    133 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
    134   // Return true if the given pid is one of our child processes.
    135   // Assumes that the current pid is the root of all pids of the current
    136   // instance.
    137   bool IsSameChromeInstance(pid_t pid);
    138 
    139   // Extract the process's pid from a symbol link path and if it is on
    140   // the same host, kill the process, unlink the lock file and return true.
    141   // If the process is part of the same chrome instance, unlink the lock file
    142   // and return true without killing it.
    143   // If the process is on a different host, return false.
    144   bool KillProcessByLockPath();
    145 
    146   // Default function to kill a process, overridable by tests.
    147   void KillProcess(int pid);
    148 
    149   // Allow overriding for tests.
    150   base::ProcessId current_pid_;
    151 
    152   // Function to call when the other process is hung and needs to be killed.
    153   // Allows overriding for tests.
    154   base::Callback<void(int)> kill_callback_;
    155 
    156   // Path in file system to the socket.
    157   base::FilePath socket_path_;
    158 
    159   // Path in file system to the lock.
    160   base::FilePath lock_path_;
    161 
    162   // Path in file system to the cookie file.
    163   base::FilePath cookie_path_;
    164 
    165   // Temporary directory to hold the socket.
    166   base::ScopedTempDir socket_dir_;
    167 
    168   // Helper class for linux specific messages.  LinuxWatcher is ref counted
    169   // because it posts messages between threads.
    170   class LinuxWatcher;
    171   scoped_refptr<LinuxWatcher> watcher_;
    172 #elif defined(OS_MACOSX)
    173   // Path in file system to the lock.
    174   base::FilePath lock_path_;
    175 
    176   // File descriptor associated with the lockfile, valid between
    177   // |Create()| and |Cleanup()|.  Two instances cannot have a lock on
    178   // the same file at the same time.
    179   int lock_fd_;
    180 #endif
    181 
    182   DISALLOW_COPY_AND_ASSIGN(ProcessSingleton);
    183 };
    184 
    185 #endif  // CHROME_BROWSER_PROCESS_SINGLETON_H_
    186