This source file includes following definitions.
- RelauncherTypeArg
- RelaunchApp
- RelaunchAppWithHelper
- RelauncherSynchronizeWithParent
- RelauncherMain
#include "chrome/browser/mac/relauncher.h"
#include <ApplicationServices/ApplicationServices.h>
#include <AvailabilityMacros.h>
#include <crt_externs.h>
#include <dlfcn.h>
#include <string.h>
#include <sys/event.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/mac/mac_logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/path_service.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/launch.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "chrome/browser/mac/install_from_dmg.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/main_function_params.h"
namespace mac_relauncher {
const char* const kRelauncherDMGDeviceArg = "--dmg-device=";
namespace {
const int kRelauncherSyncFD = STDERR_FILENO + 1;
const char kRelauncherArgSeparator[] = "---";
const char kRelauncherBackgroundArg[] = "--background";
const char kPSNArg[] = "-psn_";
std::string RelauncherTypeArg() {
return base::StringPrintf("--%s=%s",
switches::kProcessType,
switches::kRelauncherProcess);
}
}
bool RelaunchApp(const std::vector<std::string>& args) {
base::FilePath child_path;
if (!PathService::Get(content::CHILD_PROCESS_EXE, &child_path)) {
LOG(ERROR) << "No CHILD_PROCESS_EXE";
return false;
}
std::vector<std::string> relauncher_args;
return RelaunchAppWithHelper(child_path.value(), 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);
relaunch_args.push_back(RelauncherTypeArg());
if (!base::mac::AmIForeground()) {
relaunch_args.push_back(kRelauncherBackgroundArg);
}
relaunch_args.insert(relaunch_args.end(),
relauncher_args.begin(), relauncher_args.end());
relaunch_args.push_back(kRelauncherArgSeparator);
const char alt_psn_arg[] = "--psn_";
for (size_t index = 0; index < args.size(); ++index) {
if (args[index].compare(0, strlen(kPSNArg), kPSNArg) != 0 &&
args[index].compare(0, strlen(alt_psn_arg), alt_psn_arg) != 0) {
relaunch_args.push_back(args[index]);
}
}
int pipe_fds[2];
if (HANDLE_EINTR(pipe(pipe_fds)) != 0) {
PLOG(ERROR) << "pipe";
return false;
}
base::ScopedFD pipe_read_fd(pipe_fds[0]);
base::ScopedFD pipe_write_fd(pipe_fds[1]);
COMPILE_ASSERT(kRelauncherSyncFD != STDIN_FILENO &&
kRelauncherSyncFD != STDOUT_FILENO &&
kRelauncherSyncFD != STDERR_FILENO,
kRelauncherSyncFD_must_not_conflict_with_stdio_fds);
base::FileHandleMappingVector fd_map;
fd_map.push_back(std::make_pair(pipe_write_fd.get(), kRelauncherSyncFD));
base::LaunchOptions options;
options.fds_to_remap = &fd_map;
if (!base::LaunchProcess(relaunch_args, options, NULL)) {
LOG(ERROR) << "base::LaunchProcess failed";
return false;
}
pipe_write_fd.reset();
char read_char;
int read_result = HANDLE_EINTR(read(pipe_read_fd.get(), &read_char, 1));
if (read_result != 1) {
if (read_result < 0) {
PLOG(ERROR) << "read";
} else {
LOG(ERROR) << "read: unexpected result " << read_result;
}
return false;
}
return true;
}
namespace {
void RelauncherSynchronizeWithParent() {
base::ScopedFD relauncher_sync_fd(kRelauncherSyncFD);
int parent_pid = getppid();
if (parent_pid == 1) {
LOG(ERROR) << "unexpected parent_pid";
return;
}
base::ScopedFD kq(kqueue());
if (!kq.is_valid()) {
PLOG(ERROR) << "kqueue";
return;
}
struct kevent change = { 0 };
EV_SET(&change, parent_pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
if (kevent(kq.get(), &change, 1, NULL, 0, NULL) == -1) {
PLOG(ERROR) << "kevent (add)";
return;
}
if (HANDLE_EINTR(write(relauncher_sync_fd.get(), "", 1)) != 1) {
PLOG(ERROR) << "write";
return;
}
struct kevent event;
int events = kevent(kq.get(), NULL, 0, &event, 1, NULL);
if (events != 1) {
if (events < 0) {
PLOG(ERROR) << "kevent (monitor)";
} else {
LOG(ERROR) << "kevent (monitor): unexpected result " << events;
}
return;
}
if (event.filter != EVFILT_PROC ||
event.fflags != NOTE_EXIT ||
event.ident != static_cast<uintptr_t>(parent_pid)) {
LOG(ERROR) << "kevent (monitor): unexpected event, filter " << event.filter
<< ", fflags " << event.fflags << ", ident " << event.ident;
return;
}
}
}
namespace internal {
int RelauncherMain(const content::MainFunctionParams& main_parameters) {
const int* argcp = _NSGetArgc();
if (!argcp) {
NOTREACHED();
return 1;
}
int argc = *argcp;
const char* const* const* argvp = _NSGetArgv();
if (!argvp) {
NOTREACHED();
return 1;
}
const char* const* argv = *argvp;
if (argc < 4 || RelauncherTypeArg() != argv[1]) {
LOG(ERROR) << "relauncher process invoked with unexpected arguments";
return 1;
}
RelauncherSynchronizeWithParent();
base::ScopedCFTypeRef<CFMutableArrayRef> relaunch_args(
CFArrayCreateMutable(NULL, argc - 4, &kCFTypeArrayCallBacks));
if (!relaunch_args) {
LOG(ERROR) << "CFArrayCreateMutable";
return 1;
}
bool background = false;
bool in_relaunch_args = false;
std::string dmg_bsd_device_name;
bool seen_relaunch_executable = false;
std::string relaunch_executable;
const std::string relauncher_arg_separator(kRelauncherArgSeparator);
for (int argv_index = 2; argv_index < argc; ++argv_index) {
const std::string arg(argv[argv_index]);
if (arg.compare(0, strlen(kPSNArg), kPSNArg) == 0) {
continue;
}
if (!in_relaunch_args) {
if (arg == relauncher_arg_separator) {
in_relaunch_args = true;
} else if (arg == kRelauncherBackgroundArg) {
background = true;
} else if (arg.compare(0, strlen(kRelauncherDMGDeviceArg),
kRelauncherDMGDeviceArg) == 0) {
dmg_bsd_device_name.assign(arg.substr(strlen(kRelauncherDMGDeviceArg)));
}
} else {
if (!seen_relaunch_executable) {
relaunch_executable.assign(arg);
seen_relaunch_executable = true;
} else {
base::ScopedCFTypeRef<CFStringRef> arg_cf(
base::SysUTF8ToCFStringRef(arg));
if (!arg_cf) {
LOG(ERROR) << "base::SysUTF8ToCFStringRef failed for " << arg;
return 1;
}
CFArrayAppendValue(relaunch_args, arg_cf);
}
}
}
if (!seen_relaunch_executable) {
LOG(ERROR) << "nothing to relaunch";
return 1;
}
FSRef app_fsref;
if (!base::mac::FSRefFromPath(relaunch_executable, &app_fsref)) {
LOG(ERROR) << "base::mac::FSRefFromPath failed for " << relaunch_executable;
return 1;
}
LSApplicationParameters ls_parameters = {
0,
kLSLaunchDefaults | kLSLaunchAndDisplayErrors | kLSLaunchNewInstance |
(background ? kLSLaunchDontSwitch : 0),
&app_fsref,
NULL,
NULL,
relaunch_args,
NULL
};
OSStatus status = LSOpenApplication(&ls_parameters, NULL);
if (status != noErr) {
OSSTATUS_LOG(ERROR, status) << "LSOpenApplication";
return 1;
}
if (!dmg_bsd_device_name.empty()) {
EjectAndTrashDiskImage(dmg_bsd_device_name);
}
return 0;
}
}
}