Merged PR 6285331: [Git2Git] Merged PR 6278637: Expose attached client process context to cooked read trace

Related work items: MSFT-32957145

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev bdb25dc99dcb2f1ee483dffe883d0178ea9d18dc
This commit is contained in:
Dustin Howett 2021-07-22 13:39:34 +00:00
parent 01b5195275
commit 184919fb24
9 changed files with 73 additions and 48 deletions

View file

@ -34,13 +34,13 @@ using Microsoft::Console::Interactivity::ServiceLocator;
// - OriginalCursorPosition -
// - NumberOfVisibleChars
// - CtrlWakeupMask - Special client parameter to interrupt editing, end the wait, and return control to the client application
// - CommandHistory -
// - Echo -
// - InsertMode -
// - Processed -
// - Line -
// - pTempHandle - A handle to the output buffer to prevent it from being destroyed while we're using it to present 'edit line' text.
// - initialData - any text data that should be prepopulated into the buffer
// - pClientProcess - Attached process handle object
// Return Value:
// - THROW: Throws E_INVALIDARG for invalid pointers.
COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
@ -49,9 +49,9 @@ COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
_In_ size_t UserBufferSize,
_In_ PWCHAR UserBuffer,
_In_ ULONG CtrlWakeupMask,
_In_ CommandHistory* CommandHistory,
const std::wstring_view exeName,
const std::string_view initialData) :
_In_ const std::wstring_view exeName,
_In_ const std::string_view initialData,
_In_ ConsoleProcessHandle* const pClientProcess) :
ReadData(pInputBuffer, pInputReadHandleData),
_screenInfo{ screenInfo },
_bytesRead{ 0 },
@ -62,7 +62,7 @@ COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
_exeName{ exeName },
_pdwNumBytes{ nullptr },
_commandHistory{ CommandHistory },
_commandHistory{ CommandHistory::s_Find((HANDLE)pClientProcess) },
_controlKeyState{ 0 },
_ctrlWakeupMask{ CtrlWakeupMask },
_visibleCharCount{ 0 },
@ -73,7 +73,8 @@ COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
_lineInput{ WI_IsFlagSet(pInputBuffer->InputMode, ENABLE_LINE_INPUT) },
_processedInput{ WI_IsFlagSet(pInputBuffer->InputMode, ENABLE_PROCESSED_INPUT) },
_insertMode{ ServiceLocator::LocateGlobals().getConsoleInformation().GetInsertMode() },
_unicode{ false }
_unicode{ false },
_clientProcess{ pClientProcess }
{
#ifndef UNIT_TESTING
THROW_IF_FAILED(screenInfo.GetMainBuffer().AllocateIoHandle(ConsoleHandleData::HandleType::Output,
@ -1030,7 +1031,9 @@ void COOKED_READ_DATA::SavePendingInput(const size_t index, const bool multiline
WI_IsFlagSet(gci.Flags, CONSOLE_HISTORY_NODUP)));
}
Tracing::s_TraceCookedRead(_backupLimit, base::saturated_cast<ULONG>(StringLength));
Tracing::s_TraceCookedRead(_clientProcess,
_backupLimit,
base::saturated_cast<ULONG>(StringLength));
// check for alias
ProcessAliases(LineCount);

View file

@ -39,9 +39,9 @@ public:
_In_ size_t UserBufferSize,
_In_ PWCHAR UserBuffer,
_In_ ULONG CtrlWakeupMask,
_In_ CommandHistory* CommandHistory,
const std::wstring_view exeName,
const std::string_view initialData);
_In_ const std::wstring_view exeName,
_In_ const std::string_view initialData,
_In_ ConsoleProcessHandle* const pClientProcess);
~COOKED_READ_DATA() override;
COOKED_READ_DATA(COOKED_READ_DATA&&) = default;
@ -156,6 +156,8 @@ private:
bool _insertMode;
bool _unicode;
ConsoleProcessHandle* const _clientProcess;
[[nodiscard]] NTSTATUS _readCharInputLoop(const bool isUnicode, size_t& numBytes) noexcept;
[[nodiscard]] NTSTATUS _handlePostCharInputLoop(const bool isUnicode, size_t& numBytes, ULONG& controlKeyState) noexcept;

View file

@ -471,7 +471,6 @@ size_t RetrieveNumberOfSpaces(_In_ SHORT sOriginalCursorPositionX,
RETURN_HR_IF(E_FAIL, !gci.HasActiveOutputBuffer());
SCREEN_INFORMATION& screenInfo = gci.GetActiveOutputBuffer();
CommandHistory* const pCommandHistory = CommandHistory::s_Find(processData);
try
{
@ -481,9 +480,9 @@ size_t RetrieveNumberOfSpaces(_In_ SHORT sOriginalCursorPositionX,
buffer.size_bytes(), // UserBufferSize
reinterpret_cast<wchar_t*>(buffer.data()), // UserBuffer
ctrlWakeupMask, // CtrlWakeupMask
pCommandHistory, // CommandHistory
exeName, // exe name
initialData);
initialData,
reinterpret_cast<ConsoleProcessHandle*>(processData)); //pClientProcess
gci.SetCookedReadData(cookedReadData.get());
bytesRead = buffer.size_bytes(); // This parameter on the way in is the size to read, on the way out, it will be updated to what is actually read.

View file

@ -406,42 +406,33 @@ void Tracing::s_TraceInputRecord(const INPUT_RECORD& inputRecord)
}
}
void Tracing::s_TraceCookedRead(_In_reads_(cchCookedBufferLength) const wchar_t* pwchCookedBuffer, _In_ ULONG cchCookedBufferLength)
{
TraceLoggingWrite(
g_hConhostV2EventTraceProvider,
"CookedRead",
TraceLoggingCountedWideString(pwchCookedBuffer, cchCookedBufferLength, "ReadBuffer"),
TraceLoggingULong(cchCookedBufferLength, "ReadBufferLength"),
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
TraceLoggingKeyword(TraceKeywords::CookedRead));
void Tracing::s_TraceCookedRead(_In_ ConsoleProcessHandle* const pConsoleProcessHandle, _In_reads_(cchCookedBufferLength) const wchar_t* pwchCookedBuffer, _In_ ULONG cchCookedBufferLength)
{
if (TraceLoggingProviderEnabled(g_hConhostV2EventTraceProvider, 0, TraceKeywords::CookedRead)) {
TraceLoggingWrite(
g_hConhostV2EventTraceProvider,
"CookedRead",
TraceLoggingCountedWideString(pwchCookedBuffer, cchCookedBufferLength, "ReadBuffer"),
TraceLoggingULong(cchCookedBufferLength, "ReadBufferLength"),
TraceLoggingUInt32(pConsoleProcessHandle->dwProcessId, "AttachedProcessId"),
TraceLoggingUInt64(pConsoleProcessHandle->GetProcessCreationTime(), "AttachedProcessCreationTime"),
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
TraceLoggingKeyword(TraceKeywords::CookedRead));
}
}
void Tracing::s_TraceConsoleAttachDetach(_In_ const ConsoleProcessHandle* pConsoleProcessHandle, _In_ bool bIsAttach)
{
FILETIME ftCreationTime, ftDummyTime = { 0 };
ULARGE_INTEGER creationTime = { 0 };
if (TraceLoggingProviderEnabled(g_hConhostV2EventTraceProvider,
WINEVENT_LEVEL_LOG_ALWAYS,
TraceKeywords::ConsoleAttachDetach)) {
if (::GetProcessTimes(pConsoleProcessHandle->GetRawHandle(),
&ftCreationTime,
&ftDummyTime,
&ftDummyTime,
&ftDummyTime)) {
creationTime.HighPart = ftCreationTime.dwHighDateTime;
creationTime.LowPart = ftCreationTime.dwLowDateTime;
}
void Tracing::s_TraceConsoleAttachDetach(_In_ ConsoleProcessHandle* const pConsoleProcessHandle, _In_ bool bIsAttach)
{
if (TraceLoggingProviderEnabled(g_hConhostV2EventTraceProvider, 0, TraceKeywords::ConsoleAttachDetach)) {
bool bIsUserInteractive = Telemetry::Instance().IsUserInteractive();
TraceLoggingWrite(
g_hConhostV2EventTraceProvider,
"ConsoleAttachDetach",
TraceLoggingUInt32(pConsoleProcessHandle->dwProcessId, "ProcessId"),
TraceLoggingUInt64(creationTime.QuadPart, "ProcessCreationTime"),
TraceLoggingUInt32(pConsoleProcessHandle->dwProcessId, "AttachedProcessId"),
TraceLoggingUInt64(pConsoleProcessHandle->GetProcessCreationTime(), "AttachedProcessCreationTime"),
TraceLoggingBool(bIsAttach, "IsAttach"),
TraceLoggingBool(bIsUserInteractive, "IsUserInteractive"),
TraceLoggingKeyword(TIL_KEYWORD_TRACE),

View file

@ -62,8 +62,8 @@ public:
static void s_TraceWindowMessage(const MSG& msg);
static void s_TraceInputRecord(const INPUT_RECORD& inputRecord);
static void s_TraceCookedRead(_In_reads_(cchCookedBufferLength) const wchar_t* pwchCookedBuffer, _In_ ULONG cchCookedBufferLength);
static void s_TraceConsoleAttachDetach(_In_ const ConsoleProcessHandle* pConsoleProcessHandle, _In_ bool bIsAttach);
static void s_TraceCookedRead(_In_ ConsoleProcessHandle* const pConsoleProcessHandle, _In_reads_(cchCookedBufferLength) const wchar_t* pwchCookedBuffer, _In_ ULONG cchCookedBufferLength);
static void s_TraceConsoleAttachDetach(_In_ ConsoleProcessHandle* const pConsoleProcessHandle, _In_ bool bIsAttach);
static void __stdcall TraceFailure(const wil::FailureInfo& failure) noexcept;

View file

@ -132,9 +132,9 @@ public:
0,
nullptr,
0,
nullptr,
L"",
initialData);
initialData,
nullptr);
gci.SetCookedReadData(readData);
}

View file

@ -312,7 +312,7 @@
}
CATCH_RETURN();
// ReadConsole needs this to get the command history list associated with an attached process, but it can be an opaque value.
// ReadConsole needs this to get details associated with an attached process (such as the command history list, telemetry metadata).
HANDLE const hConsoleClient = (HANDLE)m->GetProcessHandle();
// ReadConsole needs this to store context information across "processed reads" e.g. reads on the same handle

View file

@ -27,7 +27,8 @@ ConsoleProcessHandle::ConsoleProcessHandle(const DWORD dwProcessId,
FALSE,
dwProcessId))),
_policy(ConsoleProcessPolicy::s_CreateInstance(_hProcess.get())),
_shimPolicy(ConsoleShimPolicy::s_CreateInstance(_hProcess.get()))
_shimPolicy(ConsoleShimPolicy::s_CreateInstance(_hProcess.get())),
_processCreationTime(0)
{
if (nullptr != _hProcess.get())
{
@ -72,3 +73,28 @@ const HANDLE ConsoleProcessHandle::GetRawHandle() const
{
return _hProcess.get();
}
// Routine Description:
// - Retrieves the process creation time (currently used in telemetry traces)
// - The creation time is lazily populated on first call
const ULONG64 ConsoleProcessHandle::GetProcessCreationTime() const
{
if (_processCreationTime == 0 && _hProcess != nullptr) {
FILETIME ftCreationTime, ftDummyTime = { 0 };
ULARGE_INTEGER creationTime = { 0 };
if (::GetProcessTimes(_hProcess.get(),
&ftCreationTime,
&ftDummyTime,
&ftDummyTime,
&ftDummyTime)) {
creationTime.HighPart = ftCreationTime.dwHighDateTime;
creationTime.LowPart = ftCreationTime.dwLowDateTime;
}
_processCreationTime = creationTime.QuadPart;
}
return _processCreationTime;
}

View file

@ -44,6 +44,8 @@ public:
CD_CONNECTION_INFORMATION GetConnectionInformation(IDeviceComm* deviceComm) const;
const ULONG64 GetProcessCreationTime() const;
private:
ConsoleProcessHandle(const DWORD dwProcessId,
const DWORD dwThreadId,
@ -58,6 +60,8 @@ private:
ULONG const _ulProcessGroupId;
wil::unique_handle const _hProcess;
mutable ULONG64 _processCreationTime;
const ConsoleProcessPolicy _policy;
const ConsoleShimPolicy _shimPolicy;