Bug 1740619 - Include the launcher process in a Job object when "--wait-for-browser" is set. r=mhowell

When the launcher process is enabled, Puppeteer, or any other automation tools, cannot
have control of the lifetime of the browser process even though the `--wait-for-browser`
option is used.

This patch is to include the launcher process and the browser process to a job to enable
a launcher of the launcher process like Puppeteer to terminate the application by terminating
the launcher process if `--wait-for-browser` is set.

Differential Revision: https://phabricator.services.mozilla.com/D131170
This commit is contained in:
Toshihito Kikuchi 2021-11-17 03:52:30 +00:00
Родитель 7f3e52cd43
Коммит 68dd038b3b
2 изменённых файлов: 82 добавлений и 3 удалений

Просмотреть файл

@ -49,6 +49,34 @@ static mozilla::LauncherVoidResult PostCreationSetup(
aChildProcess);
}
/**
* Create a new Job object and assign |aProcess| to it. If something fails
* in this function, we return nullptr but continue without recording
* a launcher failure because it's not a critical problem to launch
* the browser process.
*/
static nsReturnRef<HANDLE> CreateJobAndAssignProcess(HANDLE aProcess) {
nsAutoHandle empty;
nsAutoHandle job(::CreateJobObjectW(nullptr, nullptr));
// Set JOB_OBJECT_LIMIT_BREAKAWAY_OK to allow the browser process
// to put child processes into a job on Win7, which does not support
// nested jobs. See CanUseJob() in sandboxBroker.cpp.
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo = {};
jobInfo.BasicLimitInformation.LimitFlags =
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK;
if (!::SetInformationJobObject(job.get(), JobObjectExtendedLimitInformation,
&jobInfo, sizeof(jobInfo))) {
return empty.out();
}
if (!::AssignProcessToJobObject(job.get(), aProcess)) {
return empty.out();
}
return job.out();
}
#if !defined( \
PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON)
# define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON \
@ -390,6 +418,11 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[],
nsAutoHandle process(pi.hProcess);
nsAutoHandle mainThread(pi.hThread);
nsAutoHandle job;
if (flags & LauncherFlags::eWaitForBrowser) {
job = CreateJobAndAssignProcess(process.get());
}
LauncherVoidResult setupResult = PostCreationSetup(
argv[0], process.get(), mainThread.get(), isSafeMode.value());
if (setupResult.isErr()) {

Просмотреть файл

@ -64,6 +64,50 @@ static wchar_t** AllocConvertUTF8toUTF16Strings(int argc, char** argv) {
return argvConverted;
}
/**
* Return true if we are in a job with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE and
* we can break away from it.
* CreateProcess fails if we try to break away from a job but it's not allowed.
* So if we cannot determine the result due to a failure, we assume we don't
* need to break away and this returns false.
*/
static bool NeedToBreakAwayFromJob() {
// If we can't determine if we are in a job, we assume we're not in a job.
BOOL inJob = FALSE;
if (!::IsProcessInJob(::GetCurrentProcess(), nullptr, &inJob)) {
return false;
}
// If there is no job, there is nothing to worry about.
if (!inJob) {
return false;
}
// If we can't get the job object flags, we assume no need to break away from
// it.
JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {};
if (!::QueryInformationJobObject(nullptr, JobObjectExtendedLimitInformation,
&job_info, sizeof(job_info), nullptr)) {
return false;
}
// If JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE is not set, no need to worry about
// the job.
if (!(job_info.BasicLimitInformation.LimitFlags &
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE)) {
return false;
}
// If we can't break away from the current job, there is nothing we can do.
if (!(job_info.BasicLimitInformation.LimitFlags &
JOB_OBJECT_LIMIT_BREAKAWAY_OK)) {
return false;
}
// We can and need to break away from the job.
return true;
}
/**
* Launch a child process with the specified arguments.
* @note argv[0] is ignored
@ -92,6 +136,9 @@ BOOL WinLaunchChild(const wchar_t* exePath, int argc, wchar_t** argv,
return FALSE;
}
DWORD creationFlags =
NeedToBreakAwayFromJob() ? CREATE_BREAKAWAY_FROM_JOB : 0;
STARTUPINFOW si = {0};
si.cb = sizeof(STARTUPINFOW);
si.lpDesktop = const_cast<LPWSTR>(L"winsta0\\Default");
@ -102,7 +149,7 @@ BOOL WinLaunchChild(const wchar_t* exePath, int argc, wchar_t** argv,
nullptr, // no special security attributes
nullptr, // no special thread attributes
FALSE, // don't inherit filehandles
0, // creation flags
creationFlags,
nullptr, // inherit my environment
nullptr, // use my current directory
&si, &pi);
@ -118,8 +165,7 @@ BOOL WinLaunchChild(const wchar_t* exePath, int argc, wchar_t** argv,
nullptr, // no special security attributes
nullptr, // no special thread attributes
FALSE, // don't inherit filehandles
0, // creation flags
environmentBlock,
creationFlags, environmentBlock,
nullptr, // use my current directory
&si, &pi);