Port our changes over
This commit is contained in:
parent
7491d5cfb5
commit
5886398f22
4 changed files with 31 additions and 184 deletions
|
@ -20,8 +20,6 @@
|
|||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/win_util.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "chrome/common/chrome_constants.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
@ -45,13 +43,6 @@ NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
|
|||
return NOTIFY_FAILED;
|
||||
|
||||
base::CommandLine command_line(*base::CommandLine::ForCurrentProcess());
|
||||
command_line.AppendSwitchASCII(
|
||||
switches::kOriginalProcessStartTime,
|
||||
base::Int64ToString(
|
||||
base::CurrentProcessInfo::CreationTime().ToInternalValue()));
|
||||
|
||||
if (fast_start)
|
||||
command_line.AppendSwitch(switches::kFastStart);
|
||||
|
||||
// Send the command line to the remote chrome window.
|
||||
// Format is "START\0<<<current directory>>>\0<<<commandline>>>".
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#ifndef CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
#define CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif // defined(OS_WIN)
|
||||
|
@ -128,8 +126,6 @@ class ProcessSingleton : public base::NonThreadSafe {
|
|||
NotificationCallback notification_callback_; // Handler for notifications.
|
||||
|
||||
#if defined(OS_WIN)
|
||||
bool EscapeVirtualization(const base::FilePath& user_data_dir);
|
||||
|
||||
HWND remote_window_; // The HWND_MESSAGE of another browser.
|
||||
base::win::MessageWindow window_; // The message-only window.
|
||||
bool is_virtualized_; // Stuck inside Microsoft Softricity VM environment.
|
||||
|
@ -180,4 +176,4 @@ class ProcessSingleton : public base::NonThreadSafe {
|
|||
DISALLOW_COPY_AND_ASSIGN(ProcessSingleton);
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
#endif // CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
|
|
|
@ -77,17 +77,10 @@
|
|||
#include "base/threading/platform_thread.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "chrome/common/chrome_constants.h"
|
||||
#include "chrome/grit/chromium_strings.h"
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/net_util.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
#include "chrome/browser/ui/process_singleton_dialog_linux.h"
|
||||
#endif
|
||||
|
||||
#if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
|
||||
#include "ui/views/linux_ui/linux_ui.h"
|
||||
#endif
|
||||
|
@ -112,6 +105,13 @@ const int kMaxACKMessageLength = arraysize(kShutdownToken) - 1;
|
|||
|
||||
const char kLockDelimiter = '-';
|
||||
|
||||
const base::FilePath::CharType kSingletonCookieFilename[] =
|
||||
FILE_PATH_LITERAL("SingletonCookie");
|
||||
|
||||
const base::FilePath::CharType kSingletonLockFilename[] = FILE_PATH_LITERAL("SingletonLock");
|
||||
const base::FilePath::CharType kSingletonSocketFilename[] =
|
||||
FILE_PATH_LITERAL("SingletonSocket");
|
||||
|
||||
// Set the close-on-exec bit on a file descriptor.
|
||||
// Returns 0 on success, -1 on failure.
|
||||
int SetCloseOnExec(int fd) {
|
||||
|
@ -304,33 +304,20 @@ bool ParseLockPath(const base::FilePath& path,
|
|||
bool DisplayProfileInUseError(const base::FilePath& lock_path,
|
||||
const std::string& hostname,
|
||||
int pid) {
|
||||
base::string16 error = l10n_util::GetStringFUTF16(
|
||||
IDS_PROFILE_IN_USE_POSIX,
|
||||
base::IntToString16(pid),
|
||||
base::ASCIIToUTF16(hostname));
|
||||
LOG(ERROR) << error;
|
||||
|
||||
if (g_disable_prompt)
|
||||
return false;
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
base::string16 relaunch_button_text = l10n_util::GetStringUTF16(
|
||||
IDS_PROFILE_IN_USE_LINUX_RELAUNCH);
|
||||
return ShowProcessSingletonDialog(error, relaunch_button_text);
|
||||
#elif defined(OS_MACOSX)
|
||||
// On Mac, always usurp the lock.
|
||||
// TODO: yolo
|
||||
return true;
|
||||
#endif
|
||||
|
||||
NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsChromeProcess(pid_t pid) {
|
||||
base::FilePath other_chrome_path(base::GetProcessExecutablePath(pid));
|
||||
|
||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||
base::FilePath exec_path(command_line->GetProgram());
|
||||
PathService::Get(base::FILE_EXE, &exec_path);
|
||||
|
||||
return (!other_chrome_path.empty() &&
|
||||
other_chrome_path.BaseName() ==
|
||||
base::FilePath(chrome::kBrowserProcessExecutableName));
|
||||
exec_path.BaseName());
|
||||
}
|
||||
|
||||
// A helper class to hold onto a socket.
|
||||
|
@ -371,7 +358,7 @@ bool ConnectSocket(ScopedSocket* socket,
|
|||
if (cookie.empty())
|
||||
return false;
|
||||
base::FilePath remote_cookie = socket_target.DirName().
|
||||
Append(chrome::kSingletonCookieFilename);
|
||||
Append(kSingletonCookieFilename);
|
||||
// Verify the cookie before connecting.
|
||||
if (!CheckCookie(remote_cookie, cookie))
|
||||
return false;
|
||||
|
@ -516,7 +503,7 @@ class ProcessSingleton::LinuxWatcher
|
|||
// reads.
|
||||
size_t bytes_read_;
|
||||
|
||||
base::OneShotTimer timer_;
|
||||
base::OneShotTimer<SocketReader> timer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SocketReader);
|
||||
};
|
||||
|
@ -731,9 +718,9 @@ ProcessSingleton::ProcessSingleton(
|
|||
: notification_callback_(notification_callback),
|
||||
current_pid_(base::GetCurrentProcId()),
|
||||
watcher_(new LinuxWatcher(this)) {
|
||||
socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename);
|
||||
lock_path_ = user_data_dir.Append(chrome::kSingletonLockFilename);
|
||||
cookie_path_ = user_data_dir.Append(chrome::kSingletonCookieFilename);
|
||||
socket_path_ = user_data_dir.Append(kSingletonSocketFilename);
|
||||
lock_path_ = user_data_dir.Append(kSingletonLockFilename);
|
||||
cookie_path_ = user_data_dir.Append(kSingletonCookieFilename);
|
||||
|
||||
kill_callback_ = base::Bind(&ProcessSingleton::KillProcess,
|
||||
base::Unretained(this));
|
||||
|
@ -973,10 +960,10 @@ bool ProcessSingleton::Create() {
|
|||
|
||||
// Setup the socket symlink and the two cookies.
|
||||
base::FilePath socket_target_path =
|
||||
socket_dir_.path().Append(chrome::kSingletonSocketFilename);
|
||||
socket_dir_.path().Append(kSingletonSocketFilename);
|
||||
base::FilePath cookie(GenerateCookie());
|
||||
base::FilePath remote_cookie_path =
|
||||
socket_dir_.path().Append(chrome::kSingletonCookieFilename);
|
||||
socket_dir_.path().Append(kSingletonCookieFilename);
|
||||
UnlinkPath(socket_path_);
|
||||
UnlinkPath(cookie_path_);
|
||||
if (!SymlinkPath(socket_target_path, socket_path_) ||
|
||||
|
|
|
@ -20,18 +20,7 @@
|
|||
#include "base/win/registry.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/browser_process_platform_part.h"
|
||||
#include "chrome/browser/chrome_process_finder_win.h"
|
||||
#include "chrome/browser/metro_utils/metro_chrome_win.h"
|
||||
#include "chrome/browser/shell_integration.h"
|
||||
#include "chrome/browser/ui/simple_message_box.h"
|
||||
#include "chrome/common/chrome_constants.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "chrome/common/chrome_paths_internal.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
#include "chrome/grit/chromium_strings.h"
|
||||
#include "chrome/installer/util/wmi.h"
|
||||
#include "content/public/common/result_codes.h"
|
||||
#include "net/base/escape.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
@ -41,8 +30,6 @@ namespace {
|
|||
|
||||
const char kLockfile[] = "lockfile";
|
||||
|
||||
const int kMetroChromeActivationTimeoutMs = 3000;
|
||||
|
||||
// A helper class that acquires the given |mutex| while the AutoLockMutex is in
|
||||
// scope.
|
||||
class AutoLockMutex {
|
||||
|
@ -174,66 +161,14 @@ bool ProcessLaunchNotification(
|
|||
return true;
|
||||
}
|
||||
|
||||
// Returns true if Chrome needs to be relaunched into Windows 8 immersive mode.
|
||||
// Following conditions apply:-
|
||||
// 1. Windows 8 or greater.
|
||||
// 2. Not in Windows 8 immersive mode.
|
||||
// 3. Chrome is default browser.
|
||||
// 4. Process integrity level is not high.
|
||||
// 5. The profile data directory is the default directory.
|
||||
// 6. Last used mode was immersive/machine is a tablet.
|
||||
// TODO(ananta)
|
||||
// Move this function to a common place as the Windows 8 delegate_execute
|
||||
// handler can possibly use this.
|
||||
bool ShouldLaunchInWindows8ImmersiveMode(const base::FilePath& user_data_dir) {
|
||||
// Returning false from this function doesn't mean we don't launch immersive
|
||||
// mode in Aura. This function is specifically called in case when we need
|
||||
// to relaunch desktop launched chrome into immersive mode through 'relaunch'
|
||||
// menu. In case of Aura, we will use delegate_execute to do the relaunch.
|
||||
bool TerminateAppWithError() {
|
||||
// TODO: This is called when the secondary process can't ping the primary
|
||||
// process. Need to find out what to do here.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DisplayShouldKillMessageBox() {
|
||||
return chrome::ShowMessageBox(
|
||||
NULL, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
|
||||
l10n_util::GetStringUTF16(IDS_BROWSER_HUNGBROWSER_MESSAGE),
|
||||
chrome::MESSAGE_BOX_TYPE_QUESTION) !=
|
||||
chrome::MESSAGE_BOX_RESULT_NO;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Microsoft's Softricity virtualization breaks the sandbox processes.
|
||||
// So, if we detect the Softricity DLL we use WMI Win32_Process.Create to
|
||||
// break out of the virtualization environment.
|
||||
// http://code.google.com/p/chromium/issues/detail?id=43650
|
||||
bool ProcessSingleton::EscapeVirtualization(
|
||||
const base::FilePath& user_data_dir) {
|
||||
if (::GetModuleHandle(L"sftldr_wow64.dll") ||
|
||||
::GetModuleHandle(L"sftldr.dll")) {
|
||||
int process_id;
|
||||
if (!installer::WMIProcess::Launch(::GetCommandLineW(), &process_id))
|
||||
return false;
|
||||
is_virtualized_ = true;
|
||||
// The new window was spawned from WMI, and won't be in the foreground.
|
||||
// So, first we sleep while the new chrome.exe instance starts (because
|
||||
// WaitForInputIdle doesn't work here). Then we poll for up to two more
|
||||
// seconds and make the window foreground if we find it (or we give up).
|
||||
HWND hwnd = 0;
|
||||
::Sleep(90);
|
||||
for (int tries = 200; tries; --tries) {
|
||||
hwnd = chrome::FindRunningChromeWindow(user_data_dir);
|
||||
if (hwnd) {
|
||||
::SetForegroundWindow(hwnd);
|
||||
break;
|
||||
}
|
||||
::Sleep(10);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ProcessSingleton::ProcessSingleton(
|
||||
const base::FilePath& user_data_dir,
|
||||
const NotificationCallback& notification_callback)
|
||||
|
@ -242,7 +177,7 @@ ProcessSingleton::ProcessSingleton(
|
|||
lock_file_(INVALID_HANDLE_VALUE),
|
||||
user_data_dir_(user_data_dir),
|
||||
should_kill_remote_process_callback_(
|
||||
base::Bind(&DisplayShouldKillMessageBox)) {
|
||||
base::Bind(&TerminateAppWithError)) {
|
||||
}
|
||||
|
||||
ProcessSingleton::~ProcessSingleton() {
|
||||
|
@ -305,8 +240,9 @@ ProcessSingleton::NotifyOtherProcessOrCreate() {
|
|||
if (result == PROCESS_NONE)
|
||||
result = PROFILE_IN_USE;
|
||||
} else {
|
||||
g_browser_process->platform_part()->PlatformSpecificCommandLineProcessing(
|
||||
*base::CommandLine::ForCurrentProcess());
|
||||
// TODO: Figure out how to implement this
|
||||
//g_browser_process->platform_part()->PlatformSpecificCommandLineProcessing(
|
||||
// *base::CommandLine::ForCurrentProcess());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -315,12 +251,10 @@ ProcessSingleton::NotifyOtherProcessOrCreate() {
|
|||
// isn't one, create a message window with its title set to the profile
|
||||
// directory path.
|
||||
bool ProcessSingleton::Create() {
|
||||
static const wchar_t kMutexName[] = L"Local\\ChromeProcessSingletonStartup!";
|
||||
static const wchar_t kMetroActivationEventName[] =
|
||||
L"Local\\ChromeProcessSingletonStartupMetroActivation!";
|
||||
static const wchar_t kMutexName[] = L"Local\\AtomProcessSingletonStartup!";
|
||||
|
||||
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
|
||||
if (!remote_window_ && !EscapeVirtualization(user_data_dir_)) {
|
||||
if (!remote_window_) {
|
||||
// Make sure we will be the one and only process creating the window.
|
||||
// We use a named Mutex since we are protecting against multi-process
|
||||
// access. As documented, it's clearer to NOT request ownership on creation
|
||||
|
@ -339,58 +273,6 @@ bool ProcessSingleton::Create() {
|
|||
// between the time where we looked for it above and the time the mutex
|
||||
// was given to us.
|
||||
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
|
||||
|
||||
|
||||
// In Win8+, a new Chrome process launched in Desktop mode may need to be
|
||||
// transmuted into Metro Chrome (see ShouldLaunchInWindows8ImmersiveMode for
|
||||
// heuristics). To accomplish this, the current Chrome activates Metro
|
||||
// Chrome, releases the startup mutex, and waits for metro Chrome to take
|
||||
// the singleton. From that point onward, the command line for this Chrome
|
||||
// process will be sent to Metro Chrome by the usual channels.
|
||||
if (!remote_window_ && base::win::GetVersion() >= base::win::VERSION_WIN8 &&
|
||||
!base::win::IsMetroProcess()) {
|
||||
// |metro_activation_event| is created right before activating a Metro
|
||||
// Chrome (note that there can only be one Metro Chrome process; by OS
|
||||
// design); all following Desktop processes will then wait for this event
|
||||
// to be signaled by Metro Chrome which will do so as soon as it grabs
|
||||
// this singleton (should any of the waiting processes timeout waiting for
|
||||
// the signal they will try to grab the singleton for themselves which
|
||||
// will result in a forced Desktop Chrome launch in the worst case).
|
||||
base::win::ScopedHandle metro_activation_event(
|
||||
::OpenEvent(SYNCHRONIZE, FALSE, kMetroActivationEventName));
|
||||
if (!metro_activation_event.IsValid() &&
|
||||
ShouldLaunchInWindows8ImmersiveMode(user_data_dir_)) {
|
||||
// No Metro activation is under way, but the desire is to launch in
|
||||
// Metro mode: activate and rendez-vous with the activated process.
|
||||
metro_activation_event.Set(
|
||||
::CreateEvent(NULL, TRUE, FALSE, kMetroActivationEventName));
|
||||
if (!chrome::ActivateMetroChrome()) {
|
||||
// Failed to launch immersive Chrome, default to launching on Desktop.
|
||||
LOG(ERROR) << "Failed to launch immersive chrome";
|
||||
metro_activation_event.Close();
|
||||
}
|
||||
}
|
||||
|
||||
if (metro_activation_event.IsValid()) {
|
||||
// Release |only_me| (to let Metro Chrome grab this singleton) and wait
|
||||
// until the event is signaled (i.e. Metro Chrome was successfully
|
||||
// activated). Ignore timeout waiting for |metro_activation_event|.
|
||||
{
|
||||
AutoUnlockMutex auto_unlock_only_me(only_me.Get());
|
||||
|
||||
DWORD result = ::WaitForSingleObject(metro_activation_event.Get(),
|
||||
kMetroChromeActivationTimeoutMs);
|
||||
DPCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT)
|
||||
<< "Result = " << result;
|
||||
}
|
||||
|
||||
// Check if this singleton was successfully grabbed by another process
|
||||
// (hopefully Metro Chrome). Failing to do so, this process will grab
|
||||
// the singleton and launch in Desktop mode.
|
||||
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
|
||||
}
|
||||
}
|
||||
|
||||
if (!remote_window_) {
|
||||
// We have to make sure there is no Chrome instance running on another
|
||||
// machine that uses the same profile.
|
||||
|
@ -417,15 +299,6 @@ bool ProcessSingleton::Create() {
|
|||
user_data_dir_.value());
|
||||
CHECK(result && window_.hwnd());
|
||||
}
|
||||
|
||||
if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
|
||||
// Make sure no one is still waiting on Metro activation whether it
|
||||
// succeeded (i.e., this is the Metro process) or failed.
|
||||
base::win::ScopedHandle metro_activation_event(
|
||||
::OpenEvent(EVENT_MODIFY_STATE, FALSE, kMetroActivationEventName));
|
||||
if (metro_activation_event.IsValid())
|
||||
::SetEvent(metro_activation_event.Get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue