Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persist inbox conhost; delegate control activities to it via a pipe #10415

Merged
20 commits merged into from
Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1942,6 +1942,7 @@ REGSTR
reingest
Relayout
RELBINPATH
remoting
Remoting
renamer
renderengine
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/CascadiaPackage/Package-Dev.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
<com:Extension Category="windows.comInterface">
<com:ComInterface>
<com:ProxyStub Id="DEC4804D-56D1-4F73-9FBE-6828E7C85C56" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
<com:Interface Id="2B607BC1-43EB-40C3-95AE-2856ADDB7F23" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
</com:ComInterface>
</com:Extension>
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/CascadiaPackage/Package-Pre.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
<com:Extension Category="windows.comInterface">
<com:ComInterface>
<com:ProxyStub Id="1833E661-CC81-4DD0-87C6-C2F74BD39EFA" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
<com:Interface Id="2B607BC1-43EB-40C3-95AE-2856ADDB7F23" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
</com:ComInterface>
</com:Extension>
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/CascadiaPackage/Package.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
<com:Extension Category="windows.comInterface">
<com:ComInterface>
<com:ProxyStub Id="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
<com:Interface Id="2B607BC1-43EB-40C3-95AE-2856ADDB7F23" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
</com:ComInterface>
</com:Extension> -->
Expand Down
2 changes: 1 addition & 1 deletion src/host/PtySignalInputThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ void PtySignalInputThread::ConnectConsole() noexcept
// - The ThreadProc for the PTY Signal Input Thread.
// Return Value:
// - S_OK if the thread runs to completion.
// - Otherwise it may cause an application termination another route and never return.
// - Otherwise it may cause an application termination and never return.
[[nodiscard]] HRESULT PtySignalInputThread::_InputThread()
{
unsigned short signalId;
Expand Down
24 changes: 22 additions & 2 deletions src/host/exe/CConsoleHandoff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,18 @@ static HRESULT _duplicateHandle(const HANDLE in, HANDLE& out)
// - server - Console driver server handle
// - inputEvent - Event already established that we signal when new input data is available in case the driver is waiting on us
// - msg - Portable attach message containing just enough descriptor payload to get us started in servicing it
// - inboxProcess - Handle to the inbox process so we can watch it to see if it disappears on us.
// - process - Handle to our process for waiting for us to exit
HRESULT CConsoleHandoff::EstablishHandoff(HANDLE server,
HANDLE inputEvent,
PCCONSOLE_PORTABLE_ATTACH_MSG msg)
PCCONSOLE_PORTABLE_ATTACH_MSG msg,
HANDLE signalPipe,
HANDLE inboxProcess,
HANDLE* process)
try
{
RETURN_HR_IF(E_INVALIDARG, !process);

// Fill the descriptor portion of a fresh api message with the received data.
// The descriptor portion is the "received" packet from the last ask of the driver.
// The other portions are unnecessary as they track the other buffer state, error codes,
Expand All @@ -53,9 +60,22 @@ try
// Making our own duplicate copy ensures they hang around in our lifetime.
RETURN_IF_FAILED(_duplicateHandle(server, server));
RETURN_IF_FAILED(_duplicateHandle(inputEvent, inputEvent));
RETURN_IF_FAILED(_duplicateHandle(signalPipe, signalPipe));
RETURN_IF_FAILED(_duplicateHandle(inboxProcess, inboxProcess));

// Now perform the handoff.
RETURN_IF_FAILED(ConsoleEstablishHandoff(server, inputEvent, &apiMsg));
RETURN_IF_FAILED(ConsoleEstablishHandoff(server, inputEvent, signalPipe, inboxProcess, &apiMsg));

// Give back a copy of our own process handle to be tracked.
wil::unique_handle duplicatedHandle;
RETURN_IF_WIN32_BOOL_FALSE(DuplicateHandle(GetCurrentProcess(),
GetCurrentProcess(),
GetCurrentProcess(),
&duplicatedHandle,
SYNCHRONIZE,
FALSE,
0));
*process = duplicatedHandle.release();
miniksa marked this conversation as resolved.
Show resolved Hide resolved

return S_OK;
}
Expand Down
5 changes: 4 additions & 1 deletion src/host/exe/CConsoleHandoff.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ struct __declspec(uuid(__CLSID_CConsoleHandoff))
#pragma region IConsoleHandoff
STDMETHODIMP EstablishHandoff(HANDLE server,
HANDLE inputEvent,
PCCONSOLE_PORTABLE_ATTACH_MSG msg);
PCCONSOLE_PORTABLE_ATTACH_MSG msg,
HANDLE signalPipe,
HANDLE inboxProcess,
HANDLE* process);

#pragma endregion
};
Expand Down
2 changes: 2 additions & 0 deletions src/host/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class Globals

std::optional<CLSID> handoffConsoleClsid;
std::optional<CLSID> handoffTerminalClsid;
wil::unique_hfile handoffInboxConsoleHandle;
wil::unique_threadpool_wait handoffInboxConsoleExitWait;

#ifdef UNIT_TESTING
void EnableConptyModeForTests(std::unique_ptr<Microsoft::Console::Render::VtEngine> vtRenderEngine);
Expand Down
7 changes: 5 additions & 2 deletions src/host/proxy/IConsoleHandoff.idl
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ typedef const CONSOLE_PORTABLE_ATTACH_MSG* PCCONSOLE_PORTABLE_ATTACH_MSG;

[
object,
uuid(2B607BC1-43EB-40C3-95AE-2856ADDB7F23)
uuid(E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4)
] interface IConsoleHandoff : IUnknown
{
HRESULT EstablishHandoff([in, system_handle(sh_file)] HANDLE server,
[in, system_handle(sh_event)] HANDLE inputEvent,
[in, ref] PCCONSOLE_PORTABLE_ATTACH_MSG msg);
[in, ref] PCCONSOLE_PORTABLE_ATTACH_MSG msg,
[in, system_handle(sh_pipe)] HANDLE signalPipe,
[in, system_handle(sh_process)] HANDLE inboxProcess,
[out, system_handle(sh_process)] HANDLE* process);
};

34 changes: 22 additions & 12 deletions src/host/srvinit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "../interactivity/inc/ServiceLocator.hpp"
#include "../interactivity/base/ApiDetector.hpp"
#include "../interactivity/base/RemoteConsoleControl.hpp"

#include "renderData.hpp"
#include "../renderer/base/renderer.hpp"
Expand Down Expand Up @@ -364,6 +365,8 @@ HRESULT ConsoleCreateIoThread(_In_ HANDLE Server,
// from the driver... or an S_OK success.
[[nodiscard]] HRESULT ConsoleEstablishHandoff([[maybe_unused]] _In_ HANDLE Server,
[[maybe_unused]] HANDLE driverInputEvent,
[[maybe_unused]] HANDLE hostSignalPipe,
[[maybe_unused]] HANDLE hostProcessHandle,
[[maybe_unused]] PCONSOLE_API_MSG connectMessage)
try
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you'll probably merge conflict near here because of til::feature

Expand All @@ -388,6 +391,22 @@ try
return E_NOT_SET;
}

// Capture handle to the inbox process into a unique handle holder.
g.handoffInboxConsoleHandle.reset(hostProcessHandle);

// Set up a threadpool waiter to shutdown everything if the inbox process disappears.
g.handoffInboxConsoleExitWait.reset(CreateThreadpoolWait(
[](PTP_CALLBACK_INSTANCE /*callbackInstance*/, PVOID /*context*/, PTP_WAIT /*wait*/, TP_WAIT_RESULT /*waitResult*/) noexcept {
ServiceLocator::RundownAndExit(E_APPLICATION_MANAGER_NOT_RUNNING);
},
nullptr,
nullptr));

miniksa marked this conversation as resolved.
Show resolved Hide resolved
SetThreadpoolWait(g.handoffInboxConsoleExitWait.get(), g.handoffInboxConsoleHandle.get(), nullptr);
lhecker marked this conversation as resolved.
Show resolved Hide resolved

std::unique_ptr<IConsoleControl> remoteControl = std::make_unique<Microsoft::Console::Interactivity::RemoteConsoleControl>(hostSignalPipe);
RETURN_IF_NTSTATUS_FAILED(ServiceLocator::SetConsoleControlInstance(std::move(remoteControl)));

wil::unique_handle signalPipeTheirSide;
wil::unique_handle signalPipeOurSide;

Expand All @@ -397,20 +416,11 @@ try
wil::unique_handle outPipeTheirSide;
wil::unique_handle outPipeOurSide;

SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
// Mark inheritable for signal handle when creating. It'll have the same value on the other side.
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = nullptr;

RETURN_IF_WIN32_BOOL_FALSE(CreatePipe(signalPipeOurSide.addressof(), signalPipeTheirSide.addressof(), nullptr, 0));
RETURN_IF_WIN32_BOOL_FALSE(SetHandleInformation(signalPipeTheirSide.get(), HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT));

RETURN_IF_WIN32_BOOL_FALSE(CreatePipe(inPipeOurSide.addressof(), inPipeTheirSide.addressof(), nullptr, 0));
RETURN_IF_WIN32_BOOL_FALSE(SetHandleInformation(inPipeTheirSide.get(), HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT));

RETURN_IF_WIN32_BOOL_FALSE(CreatePipe(outPipeTheirSide.addressof(), outPipeOurSide.addressof(), nullptr, 0));
RETURN_IF_WIN32_BOOL_FALSE(SetHandleInformation(outPipeTheirSide.get(), HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT));

wil::unique_handle clientProcess{ OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, TRUE, static_cast<DWORD>(connectMessage->Descriptor.Process)) };
RETURN_LAST_ERROR_IF_NULL(clientProcess.get());
Expand All @@ -434,9 +444,9 @@ try
serverProcess,
clientProcess.get()));

inPipeTheirSide.release();
outPipeTheirSide.release();
signalPipeTheirSide.release();
inPipeTheirSide.reset();
outPipeTheirSide.reset();
signalPipeTheirSide.reset();
miniksa marked this conversation as resolved.
Show resolved Hide resolved

const auto commandLine = fmt::format(FMT_COMPILE(L" --headless --signal {:#x}"), (int64_t)signalPipeOurSide.release());

Expand Down
2 changes: 2 additions & 0 deletions src/host/srvinit.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ PWSTR TranslateConsoleTitle(_In_ PCWSTR pwszConsoleTitle, const BOOL fUnexpand,

[[nodiscard]] HRESULT ConsoleEstablishHandoff(_In_ HANDLE Server,
HANDLE driverInputEvent,
HANDLE hostSignalPipe,
HANDLE hostProcessHandle,
PCONSOLE_API_MSG connectMessage);

void ConsoleCheckDebug();
33 changes: 33 additions & 0 deletions src/inc/HostSignals.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace Microsoft::Console
{
// These values match the enumeration values of `ControlType` for the `ConsoleControl` class
// but are defined here similarly to not pollute other projects.
// They don't *have* to be the same values, but matching them seemed to make sense.
enum class HostSignals : uint8_t
{
NotifyApp = 1u,
SetForeground = 5u,
EndTask = 7u
};

struct HostSignalNotifyAppData
{
uint32_t sizeInBytes;
uint32_t processId;
};

struct HostSignalSetForegroundData
{
uint32_t sizeInBytes;
uint32_t processId;
bool isForeground;
};

struct HostSignalEndTaskData
{
uint32_t sizeInBytes;
uint32_t processId;
uint32_t eventType;
uint32_t ctrlFlags;
};
};
Loading