Merge pull request #3175 from atom/improve-make-single-instance

Fix some problems of makeSingleInstance
This commit is contained in:
Cheng Zhao 2015-10-23 09:13:57 +08:00
commit e3ce1b50ec
17 changed files with 174 additions and 253 deletions

View file

@ -19,7 +19,6 @@
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/command_line_converter.h"
#include "atom/common/node_includes.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h"
@ -112,6 +111,23 @@ int GetPathConstant(const std::string& name) {
return -1;
}
bool NotificationCallbackWrapper(
const ProcessSingleton::NotificationCallback& callback,
const base::CommandLine::StringVector& cmd,
const base::FilePath& cwd) {
// Make sure the callback is called after app gets ready.
if (Browser::Get()->is_ready()) {
callback.Run(cmd, cwd);
} else {
scoped_refptr<base::SingleThreadTaskRunner> task_runner(
base::ThreadTaskRunnerHandle::Get());
task_runner->PostTask(
FROM_HERE, base::Bind(base::IgnoreResult(callback), cmd, cwd));
}
// ProcessSingleton needs to know whether current process is quiting.
return !Browser::Get()->is_shutting_down();
}
void OnClientCertificateSelected(
v8::Isolate* isolate,
std::shared_ptr<content::ClientCertificateDelegate> delegate,
@ -163,10 +179,7 @@ void App::OnQuit() {
Emit("quit");
if (process_singleton_.get()) {
if (process_notify_result_ == ProcessSingleton::PROCESS_NONE) {
process_singleton_->Cleanup();
}
process_singleton_.reset();
}
}
@ -196,10 +209,6 @@ void App::OnFinishLaunching() {
auto handle = Session::CreateFrom(isolate(), browser_context);
default_session_.Reset(isolate(), handle.ToV8());
if (process_singleton_.get()) {
process_singleton_startup_lock_->Unlock();
}
Emit("ready");
}
@ -281,35 +290,24 @@ v8::Local<v8::Value> App::DefaultSession(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, default_session_);
}
bool App::MakeSingleInstance(ProcessSingleton::NotificationCallback callback) {
base::FilePath userDir;
PathService::Get(brightray::DIR_USER_DATA, &userDir);
if (!process_singleton_.get()) {
auto browser = Browser::Get();
process_singleton_startup_lock_.reset(
new ProcessSingletonStartupLock(callback));
process_singleton_.reset(
new ProcessSingleton(
userDir,
process_singleton_startup_lock_->AsNotificationCallback()));
if (browser->is_ready()) {
process_singleton_startup_lock_->Unlock();
}
process_notify_result_ = process_singleton_->NotifyOtherProcessOrCreate();
}
switch (process_notify_result_) {
case ProcessSingleton::NotifyResult::PROCESS_NONE:
bool App::MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback) {
if (process_singleton_.get())
return false;
base::FilePath user_dir;
PathService::Get(brightray::DIR_USER_DATA, &user_dir);
process_singleton_.reset(new ProcessSingleton(
user_dir, base::Bind(NotificationCallbackWrapper, callback)));
switch (process_singleton_->NotifyOtherProcessOrCreate()) {
case ProcessSingleton::NotifyResult::LOCK_ERROR:
case ProcessSingleton::NotifyResult::PROFILE_IN_USE:
case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED:
process_singleton_.reset();
return true;
default:
case ProcessSingleton::NotifyResult::PROCESS_NONE:
default: // Shouldn't be needed, but VS warns if it is not there.
return false;
}
}

View file

@ -11,7 +11,6 @@
#include "atom/browser/browser_observer.h"
#include "atom/common/native_mate_converters/callback.h"
#include "chrome/browser/process_singleton.h"
#include "chrome/browser/process_singleton_startup_lock.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "native_mate/handle.h"
@ -68,19 +67,15 @@ class App : public mate::EventEmitter,
void SetDesktopName(const std::string& desktop_name);
void SetAppUserModelId(const std::string& app_id);
void AllowNTLMCredentialsForAllDomains(bool should_allow);
bool MakeSingleInstance(ProcessSingleton::NotificationCallback callback);
bool MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback);
std::string GetLocale();
v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate);
v8::Global<v8::Value> default_session_;
scoped_ptr<ProcessSingleton> process_singleton_;
scoped_ptr<ProcessSingletonStartupLock> process_singleton_startup_lock_;
ProcessSingleton::NotifyResult process_notify_result_;
DISALLOW_COPY_AND_ASSIGN(App);
};

View file

@ -62,7 +62,6 @@ void AtomBrowserMainParts::PreEarlyInitialization() {
void AtomBrowserMainParts::PostEarlyInitialization() {
brightray::BrowserMainParts::PostEarlyInitialization();
{
// Temporary set the bridge_task_runner_ as current thread's task runner,
// so we can fool gin::PerIsolateData to use it as its task runner, instead
// of getting current message loop's task runner, which is null for now.
@ -72,7 +71,6 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
// The ProxyResolverV8 has setup a complete V8 environment, in order to
// avoid conflicts we only initialize our V8 environment after that.
js_env_.reset(new JavascriptEnvironment);
}
node_bindings_->Initialize();
@ -107,6 +105,7 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
1000));
brightray::BrowserMainParts::PreMainMessageLoopRun();
BridgeTaskRunner::MessageLoopIsReady();
#if defined(USE_X11)
libgtk2ui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());

View file

@ -8,13 +8,33 @@
namespace atom {
// static
std::vector<BridgeTaskRunner::TaskPair> BridgeTaskRunner::tasks_;
std::vector<BridgeTaskRunner::TaskPair> BridgeTaskRunner::non_nestable_tasks_;
// static
void BridgeTaskRunner::MessageLoopIsReady() {
auto message_loop = base::MessageLoop::current();
CHECK(message_loop);
for (const TaskPair& task : tasks_) {
message_loop->task_runner()->PostDelayedTask(
base::get<0>(task), base::get<1>(task), base::get<2>(task));
}
for (const TaskPair& task : non_nestable_tasks_) {
message_loop->task_runner()->PostNonNestableDelayedTask(
base::get<0>(task), base::get<1>(task), base::get<2>(task));
}
}
bool BridgeTaskRunner::PostDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current();
if (!message_loop)
return false;
if (!message_loop) {
tasks_.push_back(base::MakeTuple(from_here, task, delay));
return true;
}
return message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
}
@ -22,7 +42,7 @@ bool BridgeTaskRunner::PostDelayedTask(
bool BridgeTaskRunner::RunsTasksOnCurrentThread() const {
auto message_loop = base::MessageLoop::current();
if (!message_loop)
return false;
return true;
return message_loop->task_runner()->RunsTasksOnCurrentThread();
}
@ -32,8 +52,10 @@ bool BridgeTaskRunner::PostNonNestableDelayedTask(
const base::Closure& task,
base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current();
if (!message_loop)
return false;
if (!message_loop) {
non_nestable_tasks_.push_back(base::MakeTuple(from_here, task, delay));
return true;
}
return message_loop->task_runner()->PostNonNestableDelayedTask(
from_here, task, delay);

View file

@ -5,17 +5,23 @@
#ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#include <vector>
#include "base/single_thread_task_runner.h"
#include "base/tuple.h"
namespace atom {
// Post all tasks to the current message loop's task runner if available,
// otherwise fail silently.
// otherwise delay the work until message loop is ready.
class BridgeTaskRunner : public base::SingleThreadTaskRunner {
public:
BridgeTaskRunner() {}
~BridgeTaskRunner() override {}
// Called when message loop is ready.
static void MessageLoopIsReady();
// base::SingleThreadTaskRunner:
bool PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
@ -27,6 +33,11 @@ class BridgeTaskRunner : public base::SingleThreadTaskRunner {
base::TimeDelta delay) override;
private:
using TaskPair = base::Tuple<
tracked_objects::Location, base::Closure, base::TimeDelta>;
static std::vector<TaskPair> tasks_;
static std::vector<TaskPair> non_nestable_tasks_;
DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner);
};

View file

@ -53,8 +53,14 @@ void Browser::Shutdown() {
is_quiting_ = true;
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());
if (base::MessageLoop::current()) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
} else {
// There is no message loop available so we are in early stage.
exit(0);
}
}
std::string Browser::GetVersion() const {

View file

@ -130,6 +130,7 @@ class Browser : public WindowListObserver {
observers_.RemoveObserver(obs);
}
bool is_shutting_down() const { return is_shutdown_; }
bool is_quiting() const { return is_quiting_; }
bool is_ready() const { return is_ready_; }

View file

@ -41,7 +41,7 @@ void FatalErrorCallback(const char* location, const char* message) {
}
void Log(const base::string16& message) {
std::cout << message;
std::cout << message << std::flush;
}
} // namespace

View file

@ -1,38 +0,0 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_COMMAND_LINE_CONVERTER_H_
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_COMMAND_LINE_CONVERTER_H_
#include <string>
#include "atom/common/native_mate_converters/string16_converter.h"
#include "base/command_line.h"
namespace mate {
template<>
struct Converter<base::CommandLine> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const base::CommandLine& val) {
return Converter<base::CommandLine::StringType>::ToV8(
isolate, val.GetCommandLineString());
}
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
base::CommandLine* out) {
base::FilePath::StringType path;
if (Converter<base::FilePath::StringType>::FromV8(isolate, val, &path)) {
*out = base::CommandLine(base::FilePath(path));
return true;
} else {
return false;
}
}
};
} // namespace mate
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_COMMAND_LINE_CONVERTER_H_

View file

@ -42,8 +42,6 @@ NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
if (!thread_id || !process_id)
return NOTIFY_FAILED;
base::CommandLine command_line(*base::CommandLine::ForCurrentProcess());
// Send the command line to the remote chrome window.
// Format is "START\0<<<current directory>>>\0<<<commandline>>>".
std::wstring to_send(L"START\0", 6); // want the NULL in the string.
@ -52,7 +50,7 @@ NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
return NOTIFY_FAILED;
to_send.append(cur_dir.value());
to_send.append(L"\0", 1); // Null separator.
to_send.append(command_line.GetCommandLineString());
to_send.append(::GetCommandLineW());
to_send.append(L"\0", 1); // Null separator.
// Allow the current running browser window to make itself the foreground

View file

@ -60,7 +60,7 @@ class ProcessSingleton : public base::NonThreadSafe {
// handled within the current browser instance or false if the remote process
// should handle it (i.e., because the current process is shutting down).
using NotificationCallback =
base::Callback<bool(const base::CommandLine& command_line,
base::Callback<bool(const base::CommandLine::StringVector& command_line,
const base::FilePath& current_directory)>;
ProcessSingleton(const base::FilePath& user_data_dir,
@ -133,6 +133,9 @@ class ProcessSingleton : public base::NonThreadSafe {
base::FilePath user_data_dir_;
ShouldKillRemoteProcessCallback should_kill_remote_process_callback_;
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
// Start listening to the socket.
void StartListening(int sock);
// Return true if the given pid is one of our child processes.
// Assumes that the current pid is the root of all pids of the current
// instance.

View file

@ -52,6 +52,7 @@
#include <set>
#include <string>
#include "atom/common/atom_command_line.h"
#include "base/base_paths.h"
#include "base/basictypes.h"
#include "base/bind.h"
@ -316,8 +317,7 @@ bool IsChromeProcess(pid_t pid) {
PathService::Get(base::FILE_EXE, &exec_path);
return (!other_chrome_path.empty() &&
other_chrome_path.BaseName() ==
exec_path.BaseName());
other_chrome_path.BaseName() == exec_path.BaseName());
}
// A helper class to hold onto a socket.
@ -600,7 +600,7 @@ void ProcessSingleton::LinuxWatcher::HandleMessage(
DCHECK(ui_message_loop_ == base::MessageLoop::current());
DCHECK(reader);
if (parent_->notification_callback_.Run(base::CommandLine(argv),
if (parent_->notification_callback_.Run(argv,
base::FilePath(current_dir))) {
// Send back "ACK" message to prevent the client process from starting up.
reader->FinishWithACK(kACKToken, arraysize(kACKToken) - 1);
@ -716,8 +716,7 @@ ProcessSingleton::ProcessSingleton(
const base::FilePath& user_data_dir,
const NotificationCallback& notification_callback)
: notification_callback_(notification_callback),
current_pid_(base::GetCurrentProcId()),
watcher_(new LinuxWatcher(this)) {
current_pid_(base::GetCurrentProcId()) {
socket_path_ = user_data_dir.Append(kSingletonSocketFilename);
lock_path_ = user_data_dir.Append(kSingletonLockFilename);
cookie_path_ = user_data_dir.Append(kSingletonCookieFilename);
@ -819,7 +818,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
return PROCESS_NONE;
to_send.append(current_dir.value());
const std::vector<std::string>& argv = cmd_line.argv();
const std::vector<std::string>& argv = atom::AtomCommandLine::argv();
for (std::vector<std::string>::const_iterator it = argv.begin();
it != argv.end(); ++it) {
to_send.push_back(kTokenDelimiter);
@ -988,13 +987,15 @@ bool ProcessSingleton::Create() {
if (listen(sock, 5) < 0)
NOTREACHED() << "listen failed: " << base::safe_strerror(errno);
DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
BrowserThread::PostTask(
BrowserThread::IO,
// In Electron the ProcessSingleton is created earlier than the IO
// thread gets created, so we have to postpone the call until message
// loop is up an running.
scoped_refptr<base::SingleThreadTaskRunner> task_runner(
base::ThreadTaskRunnerHandle::Get());
task_runner->PostTask(
FROM_HERE,
base::Bind(&ProcessSingleton::LinuxWatcher::StartListening,
watcher_.get(),
sock));
base::Bind(&ProcessSingleton::StartListening,
base::Unretained(this), sock));
return true;
}
@ -1005,6 +1006,17 @@ void ProcessSingleton::Cleanup() {
UnlinkPath(lock_path_);
}
void ProcessSingleton::StartListening(int sock) {
watcher_ = new LinuxWatcher(this);
DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&ProcessSingleton::LinuxWatcher::StartListening,
watcher_.get(),
sock));
}
bool ProcessSingleton::IsSameChromeInstance(pid_t pid) {
pid_t cur_pid = current_pid_;
while (pid != cur_pid) {

View file

@ -1,53 +0,0 @@
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/process_singleton_startup_lock.h"
#include "base/bind.h"
#include "base/logging.h"
ProcessSingletonStartupLock::ProcessSingletonStartupLock(
const ProcessSingleton::NotificationCallback& original_callback)
: locked_(true),
original_callback_(original_callback) {}
ProcessSingletonStartupLock::~ProcessSingletonStartupLock() {}
ProcessSingleton::NotificationCallback
ProcessSingletonStartupLock::AsNotificationCallback() {
return base::Bind(&ProcessSingletonStartupLock::NotificationCallbackImpl,
base::Unretained(this));
}
void ProcessSingletonStartupLock::Unlock() {
DCHECK(CalledOnValidThread());
locked_ = false;
// Replay the command lines of the messages which were received while the
// ProcessSingleton was locked. Only replay each message once.
std::set<DelayedStartupMessage> replayed_messages;
for (std::vector<DelayedStartupMessage>::const_iterator it =
saved_startup_messages_.begin();
it != saved_startup_messages_.end(); ++it) {
if (replayed_messages.find(*it) != replayed_messages.end())
continue;
original_callback_.Run(base::CommandLine(it->first), it->second);
replayed_messages.insert(*it);
}
saved_startup_messages_.clear();
}
bool ProcessSingletonStartupLock::NotificationCallbackImpl(
const base::CommandLine& command_line,
const base::FilePath& current_directory) {
if (locked_) {
// If locked, it means we are not ready to process this message because
// we are probably in a first run critical phase.
saved_startup_messages_.push_back(
std::make_pair(command_line.argv(), current_directory));
return true;
} else {
return original_callback_.Run(command_line, current_directory);
}
}

View file

@ -1,57 +0,0 @@
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PROCESS_SINGLETON_STARTUP_LOCK_H_
#define CHROME_BROWSER_PROCESS_SINGLETON_STARTUP_LOCK_H_
#include <set>
#include <utility>
#include <vector>
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/threading/non_thread_safe.h"
#include "chrome/browser/process_singleton.h"
// Provides a ProcessSingleton::NotificationCallback that can queue up
// command-line invocations during startup and execute them when startup
// completes.
//
// The object starts in a locked state. |Unlock()| must be called
// when the process is prepared to handle command-line invocations.
//
// Once unlocked, notifications are forwarded to a wrapped NotificationCallback.
class ProcessSingletonStartupLock : public base::NonThreadSafe {
public:
explicit ProcessSingletonStartupLock(
const ProcessSingleton::NotificationCallback& original_callback);
~ProcessSingletonStartupLock();
// Returns the ProcessSingleton::NotificationCallback.
// The callback is only valid during the lifetime of the
// ProcessSingletonStartupLock instance.
ProcessSingleton::NotificationCallback AsNotificationCallback();
// Executes previously queued command-line invocations and allows future
// invocations to be executed immediately.
void Unlock();
bool locked() { return locked_; }
private:
typedef std::pair<base::CommandLine::StringVector, base::FilePath>
DelayedStartupMessage;
bool NotificationCallbackImpl(const base::CommandLine& command_line,
const base::FilePath& current_directory);
bool locked_;
std::vector<DelayedStartupMessage> saved_startup_messages_;
ProcessSingleton::NotificationCallback original_callback_;
DISALLOW_COPY_AND_ASSIGN(ProcessSingletonStartupLock);
};
#endif // CHROME_BROWSER_PROCESS_SINGLETON_STARTUP_LOCK_H_

View file

@ -77,8 +77,21 @@ BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
return !*result;
}
// Convert Command line string to argv.
base::CommandLine::StringVector CommandLineStringToArgv(
const std::wstring& command_line_string) {
int num_args = 0;
wchar_t** args = NULL;
args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args);
base::CommandLine::StringVector argv;
for (int i = 0; i < num_args; ++i)
argv.push_back(std::wstring(args[i]));
LocalFree(args);
return argv;
}
bool ParseCommandLine(const COPYDATASTRUCT* cds,
base::CommandLine* parsed_command_line,
base::CommandLine::StringVector* parsed_command_line,
base::FilePath* current_directory) {
// We should have enough room for the shortest command (min_message_size)
// and also be a multiple of wchar_t bytes. The shortest command
@ -131,7 +144,7 @@ bool ParseCommandLine(const COPYDATASTRUCT* cds,
// Get command line.
const std::wstring cmd_line =
msg.substr(second_null + 1, third_null - second_null);
*parsed_command_line = base::CommandLine::FromString(cmd_line);
*parsed_command_line = CommandLineStringToArgv(cmd_line);
return true;
}
return false;
@ -149,7 +162,7 @@ bool ProcessLaunchNotification(
// Handle the WM_COPYDATA message from another process.
const COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(lparam);
base::CommandLine parsed_command_line(base::CommandLine::NO_PROGRAM);
base::CommandLine::StringVector parsed_command_line;
base::FilePath current_directory;
if (!ParseCommandLine(cds, &parsed_command_line, &current_directory)) {
*result = TRUE;

View file

@ -299,41 +299,51 @@ allowing multiple instances of your app to run, this will ensure that only a
single instance of your app is running, and other instances signal this
instance and exit.
`callback` is called when a second instance has been executed, and provides
the command-line (including Chromium flags) and the working directory of the
secondary instance. Usually applications respond to this by making their
primary window focused and non-minimized.
`callback` will be called with `callback(argv, workingDirectory)` when a second
instance has been executed. `argv` is an Array of the second instance's command
line arguments, and `workingDirectory` is its current working directory. Usually
applications respond to this by making their primary window focused and
non-minimized.
`callback` should return `true` if the message was successfully handled, or
`false` if the secondary process should retry sending it or it failed.
The `callback` is guaranteed to be executed after the `ready` event of `app`
gets emitted.
This method returns `false` if your process is the primary instance of the
application and your app should continue loading. And returns `true` if your
process has sent its parameters to another instance, and you should immediately
quit.
On OS X the system enforces single instance automatically when users try to open
a second instance of your app in Finder, and the `open-file` and `open-url`
events will be emitted for that. However when users start your app in command
line the system's single instance machanism will be bypassed and you have to
use this method to ensure single instance.
An example of activating the window of primary instance when a second instance
starts:
```js
var myWindow;
app.on('ready', function() {
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
var myWindow = null;
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
// Someone tried to run a second instance, we should focus our window
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore();
myWindow.focus();
}
// We successfully handled the command line
return true;
});
});
if (shouldQuit) {
if (shouldQuit) {
app.quit();
return;
}
}
// Create myWindow, load the rest of the app, etc...
// Create myWindow, load the rest of the app, etc...
app.on('ready', function() {
});
```
Returns a Boolean - if `false`, your process is the primary instance of the
application and your app should continue loading. If `true`, your process has
sent its parameters to another instance, and you should immediately quit.
### `app.commandLine.appendSwitch(switch[, value])`
Append a switch (with optional `value`) to Chromium's command line.

View file

@ -347,6 +347,7 @@
'chromium_src/chrome/browser/browser_process.cc',
'chromium_src/chrome/browser/browser_process.h',
'chromium_src/chrome/browser/chrome_process_finder_win.cc',
'chromium_src/chrome/browser/chrome_process_finder_win.h',
'chromium_src/chrome/browser/chrome_notification_types.h',
'chromium_src/chrome/browser/extensions/global_shortcut_listener.cc',
'chromium_src/chrome/browser/extensions/global_shortcut_listener.h',
@ -376,8 +377,8 @@
'chromium_src/chrome/browser/printing/print_preview_message_handler.cc',
'chromium_src/chrome/browser/printing/print_preview_message_handler.h',
'chromium_src/chrome/browser/process_singleton_posix.cc',
'chromium_src/chrome/browser/process_singleton_startup_lock.cc',
'chromium_src/chrome/browser/process_singleton_win.cc',
'chromium_src/chrome/browser/process_singleton.h',
'chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc',
'chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h',
'chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc',