зеркало из https://github.com/electron/electron.git
Implement Relaunch on Windows
This commit is contained in:
Родитель
a3f39e9d0b
Коммит
0646f6ea9e
|
@ -111,6 +111,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
|||
params.instance = instance;
|
||||
params.sandbox_info = &sandbox_info;
|
||||
atom::AtomCommandLine::Init(argc, argv);
|
||||
atom::AtomCommandLine::InitW(argc, wargv);
|
||||
return content::ContentMain(params);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/relauncher.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
|
@ -34,15 +33,15 @@ Browser* Browser::Get() {
|
|||
return AtomBrowserMainParts::Get()->browser();
|
||||
}
|
||||
|
||||
void Browser::Relaunch(const std::vector<std::string>& args,
|
||||
const std::string& app) {
|
||||
base::FilePath exe_path;
|
||||
PathService::Get(base::FILE_EXE, &exe_path);
|
||||
|
||||
std::vector<std::string> args_with_app(args);
|
||||
args_with_app.insert(args_with_app.begin(),
|
||||
app.empty() ? exe_path.value() : app);
|
||||
relauncher::RelaunchApp(args_with_app);
|
||||
bool Browser::Relaunch(const base::FilePath& app,
|
||||
const relauncher::StringVector& args) {
|
||||
if (app.empty()) {
|
||||
base::FilePath exe_path;
|
||||
PathService::Get(base::FILE_EXE, &exe_path);
|
||||
return relauncher::RelaunchApp(exe_path, args);
|
||||
} else {
|
||||
return relauncher::RelaunchApp(app, args);
|
||||
}
|
||||
}
|
||||
|
||||
void Browser::Quit() {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "base/observer_list.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "atom/browser/browser_observer.h"
|
||||
#include "atom/browser/relauncher.h"
|
||||
#include "atom/browser/window_list_observer.h"
|
||||
#include "native_mate/arguments.h"
|
||||
|
||||
|
@ -54,8 +55,8 @@ class Browser : public WindowListObserver {
|
|||
void Shutdown();
|
||||
|
||||
// Restart the app.
|
||||
void Relaunch(const std::vector<std::string>& args,
|
||||
const std::string& app);
|
||||
bool Relaunch(const base::FilePath& app,
|
||||
const relauncher::StringVector& args);
|
||||
|
||||
// Focus the application.
|
||||
void Focus();
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "base/logging.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/process/launch.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "content/public/common/content_paths.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "content/public/common/main_function_params.h"
|
||||
|
@ -29,12 +29,13 @@ namespace internal {
|
|||
const int kRelauncherSyncFD = STDERR_FILENO + 1;
|
||||
#endif
|
||||
|
||||
const char* kRelauncherTypeArg = "--type=relauncher";
|
||||
const char* kRelauncherArgSeparator = "---";
|
||||
const CharType* kRelauncherTypeArg = FILE_PATH_LITERAL("--type=relauncher");
|
||||
const CharType* kRelauncherArgSeparator = FILE_PATH_LITERAL("---");
|
||||
|
||||
} // namespace internal
|
||||
|
||||
bool RelaunchApp(const std::vector<std::string>& args) {
|
||||
bool RelaunchApp(const base::FilePath& app,
|
||||
const StringVector& args) {
|
||||
// Use the currently-running application's helper process. The automatic
|
||||
// update feature is careful to leave the currently-running version alone,
|
||||
// so this is safe even if the relaunch is the result of an update having
|
||||
|
@ -47,15 +48,16 @@ bool RelaunchApp(const std::vector<std::string>& args) {
|
|||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> relauncher_args;
|
||||
return RelaunchAppWithHelper(child_path.value(), relauncher_args, args);
|
||||
StringVector relauncher_args;
|
||||
return RelaunchAppWithHelper(app, child_path, relauncher_args, args);
|
||||
}
|
||||
|
||||
bool RelaunchAppWithHelper(const std::string& helper,
|
||||
const std::vector<std::string>& relauncher_args,
|
||||
const std::vector<std::string>& args) {
|
||||
std::vector<std::string> relaunch_args;
|
||||
relaunch_args.push_back(helper);
|
||||
bool RelaunchAppWithHelper(const base::FilePath& app,
|
||||
const base::FilePath& helper,
|
||||
const StringVector& relauncher_args,
|
||||
const StringVector& args) {
|
||||
StringVector relaunch_args;
|
||||
relaunch_args.push_back(helper.value());
|
||||
relaunch_args.push_back(internal::kRelauncherTypeArg);
|
||||
|
||||
relaunch_args.insert(relaunch_args.end(),
|
||||
|
@ -63,6 +65,7 @@ bool RelaunchAppWithHelper(const std::string& helper,
|
|||
|
||||
relaunch_args.push_back(internal::kRelauncherArgSeparator);
|
||||
|
||||
relaunch_args.push_back(app.value());
|
||||
relaunch_args.insert(relaunch_args.end(), args.begin(), args.end());
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
|
@ -97,8 +100,12 @@ bool RelaunchAppWithHelper(const std::string& helper,
|
|||
base::LaunchOptions options;
|
||||
#if defined(OS_POSIX)
|
||||
options.fds_to_remap = &fd_map;
|
||||
base::Process process = base::LaunchProcess(relaunch_args, options);
|
||||
#elif defined(OS_WIN)
|
||||
base::Process process = base::LaunchProcess(
|
||||
base::JoinString(relaunch_args, L" "), options);
|
||||
#endif
|
||||
if (!base::LaunchProcess(relaunch_args, options).IsValid()) {
|
||||
if (!process.IsValid()) {
|
||||
LOG(ERROR) << "base::LaunchProcess failed";
|
||||
return false;
|
||||
}
|
||||
|
@ -106,7 +113,15 @@ bool RelaunchAppWithHelper(const std::string& helper,
|
|||
// The relauncher process is now starting up, or has started up. The
|
||||
// original parent process continues.
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_WIN)
|
||||
// Synchronize with the relauncher process.
|
||||
StringType name = internal::GetWaitEventName(process.Pid());
|
||||
HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, name.c_str());
|
||||
if (wait_event != NULL) {
|
||||
WaitForSingleObject(wait_event, 1000);
|
||||
CloseHandle(wait_event);
|
||||
}
|
||||
#elif defined(OS_POSIX)
|
||||
pipe_write_fd.reset(); // close(pipe_fds[1]);
|
||||
|
||||
// Synchronize with the relauncher process.
|
||||
|
@ -129,7 +144,11 @@ bool RelaunchAppWithHelper(const std::string& helper,
|
|||
}
|
||||
|
||||
int RelauncherMain(const content::MainFunctionParams& main_parameters) {
|
||||
const std::vector<std::string>& argv = atom::AtomCommandLine::argv();
|
||||
#if defined(OS_WIN)
|
||||
const StringVector& argv = atom::AtomCommandLine::wargv();
|
||||
#else
|
||||
const StringVector& argv = atom::AtomCommandLine::argv();
|
||||
#endif
|
||||
|
||||
if (argv.size() < 4 || argv[1] != internal::kRelauncherTypeArg) {
|
||||
LOG(ERROR) << "relauncher process invoked with unexpected arguments";
|
||||
|
@ -142,11 +161,11 @@ int RelauncherMain(const content::MainFunctionParams& main_parameters) {
|
|||
// start it in the background.
|
||||
bool in_relaunch_args = false;
|
||||
bool seen_relaunch_executable = false;
|
||||
std::string relaunch_executable;
|
||||
std::vector<std::string> relauncher_args;
|
||||
std::vector<std::string> launch_args;
|
||||
StringType relaunch_executable;
|
||||
StringVector relauncher_args;
|
||||
StringVector launch_args;
|
||||
for (size_t argv_index = 2; argv_index < argv.size(); ++argv_index) {
|
||||
const std::string& arg(argv[argv_index]);
|
||||
const StringType& arg(argv[argv_index]);
|
||||
if (!in_relaunch_args) {
|
||||
if (arg == internal::kRelauncherArgSeparator) {
|
||||
in_relaunch_args = true;
|
||||
|
|
|
@ -32,12 +32,22 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/command_line.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/process/process_handle.h"
|
||||
#endif
|
||||
|
||||
namespace content {
|
||||
struct MainFunctionParams;
|
||||
}
|
||||
|
||||
namespace relauncher {
|
||||
|
||||
using CharType = base::CommandLine::CharType;
|
||||
using StringType = base::CommandLine::StringType;
|
||||
using StringVector = base::CommandLine::StringVector;
|
||||
|
||||
// Relaunches the application using the helper application associated with the
|
||||
// currently running instance of Chrome in the parent browser process as the
|
||||
// executable for the relauncher process. |args| is an argv-style vector of
|
||||
|
@ -49,7 +59,8 @@ namespace relauncher {
|
|||
// successfully. Returns true on success, although some failures can occur
|
||||
// after this function returns true if, for example, they occur within the
|
||||
// relauncher process. Returns false when the relaunch definitely failed.
|
||||
bool RelaunchApp(const std::vector<std::string>& args);
|
||||
bool RelaunchApp(const base::FilePath& app,
|
||||
const StringVector& args);
|
||||
|
||||
// Identical to RelaunchApp, but uses |helper| as the path to the relauncher
|
||||
// process, and allows additional arguments to be supplied to the relauncher
|
||||
|
@ -60,22 +71,25 @@ bool RelaunchApp(const std::vector<std::string>& args);
|
|||
// able to communicate with one another. This variant can be useful to
|
||||
// relaunch the same version of Chrome from another location, using that
|
||||
// location's helper.
|
||||
bool RelaunchAppWithHelper(const std::string& helper,
|
||||
const std::vector<std::string>& relauncher_args,
|
||||
const std::vector<std::string>& args);
|
||||
bool RelaunchAppWithHelper(const base::FilePath& app,
|
||||
const base::FilePath& helper,
|
||||
const StringVector& relauncher_args,
|
||||
const StringVector& args);
|
||||
|
||||
// The entry point from ChromeMain into the relauncher process.
|
||||
int RelauncherMain(const content::MainFunctionParams& main_parameters);
|
||||
|
||||
namespace internal {
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// The "magic" file descriptor that the relauncher process' write side of the
|
||||
// pipe shows up on. Chosen to avoid conflicting with stdin, stdout, and
|
||||
// stderr.
|
||||
extern const int kRelauncherSyncFD;
|
||||
#endif
|
||||
|
||||
// The "type" argument identifying a relauncher process ("--type=relauncher").
|
||||
extern const char* kRelauncherTypeArg;
|
||||
extern const CharType* kRelauncherTypeArg;
|
||||
|
||||
// The argument separating arguments intended for the relauncher process from
|
||||
// those intended for the relaunched process. "---" is chosen instead of "--"
|
||||
|
@ -84,7 +98,11 @@ extern const char* kRelauncherTypeArg;
|
|||
// arguments intended for the relaunched process, to get the correct settings
|
||||
// for such things as logging and the user-data-dir in case it affects crash
|
||||
// reporting.
|
||||
extern const char* kRelauncherArgSeparator;
|
||||
extern const CharType* kRelauncherArgSeparator;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
StringType GetWaitEventName(base::ProcessId pid);
|
||||
#endif
|
||||
|
||||
// In the relauncher process, performs the necessary synchronization steps
|
||||
// with the parent by setting up a kqueue to watch for it to exit, writing a
|
||||
|
@ -94,9 +112,9 @@ extern const char* kRelauncherArgSeparator;
|
|||
// process and the best recovery approach is to attempt relaunch anyway.
|
||||
void RelauncherSynchronizeWithParent();
|
||||
|
||||
int LaunchProgram(const std::vector<std::string>& relauncher_args,
|
||||
const std::string& program,
|
||||
const std::vector<std::string>& argv);
|
||||
int LaunchProgram(const StringVector& relauncher_args,
|
||||
const StringType& program,
|
||||
const StringVector& argv);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <sys/prctl.h>
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
#include "atom/common/atom_command_line.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/relauncher.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/process/launch.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "sandbox/win/src/nt_internals.h"
|
||||
#include "sandbox/win/src/win_utils.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
|
||||
namespace relauncher {
|
||||
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
const CharType* kWaitEventName = L"ElectronRelauncherWaitEvent";
|
||||
|
||||
HANDLE GetParentProcessHandle(base::ProcessHandle handle) {
|
||||
NtQueryInformationProcessFunction NtQueryInformationProcess = nullptr;
|
||||
ResolveNTFunctionPtr("NtQueryInformationProcess", &NtQueryInformationProcess);
|
||||
if (!NtQueryInformationProcess) {
|
||||
LOG(ERROR) << "Unable to get NtQueryInformationProcess";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PROCESS_BASIC_INFORMATION pbi;
|
||||
LONG status = NtQueryInformationProcess(
|
||||
handle, ProcessBasicInformation,
|
||||
&pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
LOG(ERROR) << "NtQueryInformationProcess failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ::OpenProcess(PROCESS_ALL_ACCESS, TRUE,
|
||||
pbi.InheritedFromUniqueProcessId);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
StringType GetWaitEventName(base::ProcessId pid) {
|
||||
return base::StringPrintf(L"%s-%d", kWaitEventName, static_cast<int>(pid));
|
||||
}
|
||||
|
||||
void RelauncherSynchronizeWithParent() {
|
||||
base::Process process = base::Process::Current();
|
||||
base::win::ScopedHandle parent_process(
|
||||
GetParentProcessHandle(process.Handle()));
|
||||
|
||||
// Notify the parent process that it can quit now.
|
||||
StringType name = internal::GetWaitEventName(process.Pid());
|
||||
base::win::ScopedHandle wait_event(
|
||||
::CreateEventW(NULL, TRUE, FALSE, name.c_str()));
|
||||
::SetEvent(wait_event.Get());
|
||||
|
||||
// Wait for parent process to quit.
|
||||
WaitForSingleObject(parent_process.Get(), INFINITE);
|
||||
}
|
||||
|
||||
int LaunchProgram(const StringVector& relauncher_args,
|
||||
const StringType& program,
|
||||
const StringVector& args) {
|
||||
base::LaunchOptions options;
|
||||
base::Process process = base::LaunchProcess(
|
||||
program + L" " + base::JoinString(args, L" "), options);
|
||||
return process.IsValid() ? 0 : 1;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace relauncher
|
|
@ -12,6 +12,11 @@ namespace atom {
|
|||
// static
|
||||
std::vector<std::string> AtomCommandLine::argv_;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// static
|
||||
std::vector<std::wstring> AtomCommandLine::wargv_;
|
||||
#endif
|
||||
|
||||
// static
|
||||
void AtomCommandLine::Init(int argc, const char* const* argv) {
|
||||
// Hack around with the argv pointer. Used for process.title = "blah"
|
||||
|
@ -21,6 +26,15 @@ void AtomCommandLine::Init(int argc, const char* const* argv) {
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// static
|
||||
void AtomCommandLine::InitW(int argc, const wchar_t* const* argv) {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
wargv_.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
// static
|
||||
void AtomCommandLine::InitializeFromCommandLine() {
|
||||
|
|
|
@ -19,6 +19,11 @@ class AtomCommandLine {
|
|||
static void Init(int argc, const char* const* argv);
|
||||
static std::vector<std::string> argv() { return argv_; }
|
||||
|
||||
#if defined(OS_WIN)
|
||||
static void InitW(int argc, const wchar_t* const* argv);
|
||||
static std::vector<std::wstring> wargv() { return wargv_; }
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
// On Linux the command line has to be read from base::CommandLine since
|
||||
// it is using zygote.
|
||||
|
@ -28,6 +33,10 @@ class AtomCommandLine {
|
|||
private:
|
||||
static std::vector<std::string> argv_;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
static std::vector<std::wstring> wargv_;
|
||||
#endif
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(AtomCommandLine);
|
||||
};
|
||||
|
||||
|
|
|
@ -227,6 +227,7 @@
|
|||
'atom/browser/node_debugger.h',
|
||||
'atom/browser/relauncher_linux.cc',
|
||||
'atom/browser/relauncher_mac.cc',
|
||||
'atom/browser/relauncher_win.cc',
|
||||
'atom/browser/relauncher.cc',
|
||||
'atom/browser/relauncher.h',
|
||||
'atom/browser/render_process_preferences.cc',
|
||||
|
|
Загрузка…
Ссылка в новой задаче