1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#ifndef CHROME_BROWSER_PROCESS_SINGLETON_H_
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define CHROME_BROWSER_PROCESS_SINGLETON_H_
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#pragma once
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <windows.h>
1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif  // defined(OS_WIN)
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/basictypes.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/ref_counted.h"
183f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/non_thread_safe.h"
1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/native_widget_types.h"
2021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
2121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(OS_POSIX)
2221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/file_path.h"
2321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif  // defined(OS_POSIX)
2421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(USE_X11)
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_temp_dir.h"
2721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif  // defined(USE_X11)
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass CommandLine;
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass FilePath;
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ProcessSingleton ----------------------------------------------------------
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class allows different browser processes to communicate with
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// each other.  It is named according to the user data directory, so
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// we can be sure that no more than one copy of the application can be
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// running at once with a given data directory.
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Implementation notes:
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// - the Windows implementation uses an invisible global message window;
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// - the Linux implementation uses a Unix domain socket in the user data dir.
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass ProcessSingleton : public base::NonThreadSafe {
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  enum NotifyResult {
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PROCESS_NONE,
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PROCESS_NOTIFIED,
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PROFILE_IN_USE,
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOCK_ERROR,
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit ProcessSingleton(const FilePath& user_data_dir);
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~ProcessSingleton();
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Notify another process, if available.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Returns true if another process was found and notified, false if we
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // should continue with this process.
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Windows code roughly based on Mozilla.
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(brettw): this will not handle all cases. If two process start up too
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // close to each other, the Create() might not yet have happened for the
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // first one, so this function won't find it.
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotifyResult NotifyOtherProcess();
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Notify another process, if available.  Otherwise sets ourselves as the
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // singleton instance.  Returns PROCESS_NONE if we became the singleton
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // instance.
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotifyResult NotifyOtherProcessOrCreate();
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(OS_LINUX)
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Exposed for testing.  We use a timeout on Linux, and in tests we want
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // this timeout to be short.
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotifyResult NotifyOtherProcessWithTimeout(const CommandLine& command_line,
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             int timeout_seconds,
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             bool kill_unresponsive);
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotifyResult NotifyOtherProcessWithTimeoutOrCreate(
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const CommandLine& command_line,
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int timeout_seconds);
7921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif  // defined(OS_LINUX)
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_WIN)
82dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Used in specific cases to let us know that there is an existing instance
83dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // of Chrome running with this profile. In general, you should not use this
84dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // function. Instead consider using NotifyOtherProcessOrCreate().
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // For non profile-specific method, use
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // browser_util::IsBrowserAlreadyRunning().
87dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  bool FoundOtherProcessWindow() const {
88dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return (NULL != remote_window_);
89dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
90dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif  // defined(OS_WIN)
91dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Sets ourself up as the singleton instance.  Returns true on success.  If
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // false is returned, we are not the singleton instance and the caller must
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // exit.
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool Create();
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Clear any lock state during shutdown.
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Cleanup();
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Blocks the dispatch of CopyData messages. foreground_window refers
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to the window that should be set to the foreground if a CopyData message
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is received while the ProcessSingleton is locked.
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Lock(gfx::NativeWindow foreground_window) {
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(CalledOnValidThread());
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    locked_ = true;
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    foreground_window_ = foreground_window;
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Allows the dispatch of CopyData messages.
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Unlock() {
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(CalledOnValidThread());
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    locked_ = false;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    foreground_window_ = NULL;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool locked() {
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(CalledOnValidThread());
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return locked_;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if !defined(OS_MACOSX)
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Timeout for the current browser process to respond. 20 seconds should be
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // enough. It's only used in Windows and Linux implementations.
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const int kTimeoutInSeconds = 20;
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool locked_;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::NativeWindow foreground_window_;
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This ugly behemoth handles startup commands sent from another process.
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LRESULT OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds);
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LRESULT CALLBACK WndProc(HWND hwnd,
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           UINT message,
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           WPARAM wparam,
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           LPARAM lparam);
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static LRESULT CALLBACK WndProcStatic(HWND hwnd,
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        UINT message,
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        WPARAM wparam,
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        LPARAM lparam) {
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProcessSingleton* msg_wnd = reinterpret_cast<ProcessSingleton*>(
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetWindowLongPtr(hwnd, GWLP_USERDATA));
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return msg_wnd->WndProc(hwnd, message, wparam, lparam);
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HWND remote_window_;  // The HWND_MESSAGE of another browser.
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HWND window_;  // The HWND_MESSAGE window.
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#elif defined(USE_X11)
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Path in file system to the socket.
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath socket_path_;
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Path in file system to the lock.
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath lock_path_;
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Path in file system to the cookie file.
1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FilePath cookie_path_;
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Temporary directory to hold the socket.
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ScopedTempDir socket_dir_;
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Helper class for linux specific messages.  LinuxWatcher is ref counted
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // because it posts messages between threads.
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  class LinuxWatcher;
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<LinuxWatcher> watcher_;
168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#elif defined(OS_MACOSX)
169731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Path in file system to the lock.
170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  FilePath lock_path_;
171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
172731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // File descriptor associated with the lockfile, valid between
173731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // |Create()| and |Cleanup()|.  Two instances cannot have a lock on
174731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // the same file at the same time.
175731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int lock_fd_;
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(ProcessSingleton);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // CHROME_BROWSER_PROCESS_SINGLETON_H_
182