diff --git a/AGENTS.md b/AGENTS.md index 1a84031c..36e069a3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,14 +1,9 @@ # AGENTS Instructions - Do not ever use non-ascii characters for source code or comments (permissible inside of strings if absolutely necessary but avoid if possible) -- Do not attempt a build unless explicitly instructed. -- Do not run tests unless explicitly instructed. - Do not ever modify files in .git subfolders. -- After finishing all changes, run a conversion pass over every changed/created text file to enforce CRLF and eliminate any stray LF. -- Do not run CRLF normalization on any non-text or binary files (for example: .png, .jpg, .gif, .mp3, .wav, .fbx, .unity). Limit normalization to plain text source/config files only. -- Use this PowerShell script directly in the current shell to normalize line endings (preserves file encoding). Do not wrap it in a nested powershell -Command invocation, because nested PowerShell quoting can corrupt variable and string parsing: - - $paths = git status --porcelain | ForEach-Object { $_.Substring(3) }; foreach ($p in $paths) { if (Test-Path $p) { $bytes = [System.IO.File]::ReadAllBytes($p); $hadBom = $bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF; $sr = New-Object System.IO.StreamReader($p, $true); $text = $sr.ReadToEnd(); $enc = $sr.CurrentEncoding; $sr.Close(); if ($enc.WebName -eq "utf-8") { $enc = New-Object System.Text.UTF8Encoding($hadBom) }; $text = $text -replace "`r?`n", "`r`n"; $sw = New-Object System.IO.StreamWriter($p, $false, $enc); $sw.NewLine = "`r`n"; $sw.Write($text); $sw.Close(); } } +- After finishing all changes, use `$normalize-crlf` to normalize changed/created text files; do not run ad hoc line-ending scripts directly. - If unexpected new files appear, ignore them and continue without asking for instruction. - For value conversion casts (numeric or enum conversions), use C-style casts `(T)value` instead of `static_cast(value)`. - For const, pointer, reference, up/down, or reinterpret casts, use C++ cast syntax (`const_cast`, `dynamic_cast`, `reinterpret_cast`, etc.). - Do not bind unused names in structured bindings. Prefer binding only needed values (for example use `.first` from `emplace()` or iterate entries without destructuring unused keys). -- Do not fully qualify namespaces when not needed by local scope (for example prefer `MetricUse` or `svc::MetricUse` over `pmon::svc::MetricUse` when already inside `pmon::svc::acts` or with suitable using scope). \ No newline at end of file +- Do not fully qualify namespaces when not needed by local scope (for example prefer `MetricUse` or `svc::MetricUse` over `pmon::svc::MetricUse` when already inside `pmon::svc::acts` or with suitable using scope). diff --git a/IntelPresentMon/AppCef/CefNano.vcxproj b/IntelPresentMon/AppCef/CefNano.vcxproj index 4eeb35ba..43c99d6e 100644 --- a/IntelPresentMon/AppCef/CefNano.vcxproj +++ b/IntelPresentMon/AppCef/CefNano.vcxproj @@ -56,6 +56,7 @@ + @@ -159,7 +160,7 @@ Level3 true - _SILENCE_CXX17_RESULT_OF_DEPRECATION_WARNING;%(PreprocessorDefinitions) + PM_VER_FILE_STR="$(PresentMonFileVersion)";PM_VER_PRODUCT_STR="$(PresentMonProductVersion)";PM_BUILD_WINSDK_VERSION_STR="$(WindowsTargetPlatformVersion)";PM_BUILD_CRT_RUNTIME_STR="MultiThreadedDebug";_SILENCE_CXX17_RESULT_OF_DEPRECATION_WARNING;%(PreprocessorDefinitions) true Fast stdcpplatest @@ -187,7 +188,7 @@ true true true - NDEBUG;_SILENCE_CXX17_RESULT_OF_DEPRECATION_WARNING;%(PreprocessorDefinitions) + PM_VER_FILE_STR="$(PresentMonFileVersion)";PM_VER_PRODUCT_STR="$(PresentMonProductVersion)";PM_BUILD_WINSDK_VERSION_STR="$(WindowsTargetPlatformVersion)";PM_BUILD_CRT_RUNTIME_STR="MultiThreaded";NDEBUG;_SILENCE_CXX17_RESULT_OF_DEPRECATION_WARNING;%(PreprocessorDefinitions) true Fast stdcpplatest @@ -215,4 +216,4 @@ - \ No newline at end of file + diff --git a/IntelPresentMon/AppCef/ipm-ui-vue/src/App.vue b/IntelPresentMon/AppCef/ipm-ui-vue/src/App.vue index da393f97..679e659f 100644 --- a/IntelPresentMon/AppCef/ipm-ui-vue/src/App.vue +++ b/IntelPresentMon/AppCef/ipm-ui-vue/src/App.vue @@ -41,7 +41,7 @@ function cyclePreset() { // === Computed === const inSettings = computed(() => { const routeName = typeof route.name === 'symbol' ? route.name.toString() : route.name; - return ['capture-config', 'overlay-config', 'data-config', 'other-config', 'flash-config', 'logging-config'] + return ['capture-config', 'overlay-config', 'data-config', 'other-config', 'flash-config', 'logging-config', 'about-config'] .includes(routeName ?? '') }); const targetName = computed(() => { @@ -182,6 +182,9 @@ watch(() => loadout.widgets, async () => { Other + + About + diff --git a/IntelPresentMon/AppCef/ipm-ui-vue/src/core/api.ts b/IntelPresentMon/AppCef/ipm-ui-vue/src/core/api.ts index c0751757..e4ec2462 100644 --- a/IntelPresentMon/AppCef/ipm-ui-vue/src/core/api.ts +++ b/IntelPresentMon/AppCef/ipm-ui-vue/src/core/api.ts @@ -8,6 +8,7 @@ import { type Adapter } from './adapter' import { type Spec } from '@/core/spec' import { type Binding, type KeyOption, type ModifierOption, Action } from '@/core/hotkey' import { type EnvVars } from './env-vars' +import { type AppInfo } from './app-info' import { delayFor } from './timing' export enum FileLocation { @@ -54,6 +55,9 @@ export class Api { static async loadEnvVars(): Promise { return await this.invokeEndpointFuture('loadEnvVars', {}); } + static async getAppInfo(): Promise { + return await this.invokeEndpointFuture('getAppInfo', {}); + } static async introspect(): Promise<{metrics: Metric[], stats: Stat[], units: Unit[], adapters: Adapter[], systemDeviceId: number, defaultAdapterId: number}> { const introData = await this.invokeEndpointFuture('Introspect', {}); if (!Array.isArray(introData.metrics) || !Array.isArray(introData.stats) || diff --git a/IntelPresentMon/AppCef/ipm-ui-vue/src/core/app-info.ts b/IntelPresentMon/AppCef/ipm-ui-vue/src/core/app-info.ts new file mode 100644 index 00000000..f3c78299 --- /dev/null +++ b/IntelPresentMon/AppCef/ipm-ui-vue/src/core/app-info.ts @@ -0,0 +1,41 @@ +// Copyright (C) 2022 Intel Corporation +// SPDX-License-Identifier: MIT + +export interface AppInfo { + productName: string; + productVersion: string; + fileVersion: string; + apiVersion: string; + middlewareApiVersion: string; + buildId: string; + buildHash: string; + buildHashShort: string; + buildDateTime: string; + buildConfig: string; + buildDirty: boolean; + isDebugBuild: boolean; + compileDate: string; + compileTime: string; + serviceBuildId: string; + serviceBuildTime: string; + serviceVersion: string; + cefVersion: string; + cefVersionMajor: number; + cefVersionMinor: number; + cefVersionPatch: number; + chromeVersion: string; + chromeVersionMajor: number; + chromeVersionMinor: number; + chromeVersionBuild: number; + chromeVersionPatch: number; + cefProcessType: string; + msvcVersion: string; + winSdkVersion: string; + crtVersion: string; + crtRuntime: string; + logLevel: string; + verboseModules: string; + devModeEnabled: boolean; + debugBlocklistEnabled: boolean; + chromiumDebugEnabled: boolean; +} diff --git a/IntelPresentMon/AppCef/ipm-ui-vue/src/router/index.ts b/IntelPresentMon/AppCef/ipm-ui-vue/src/router/index.ts index 9d5a3c40..03f7f41c 100644 --- a/IntelPresentMon/AppCef/ipm-ui-vue/src/router/index.ts +++ b/IntelPresentMon/AppCef/ipm-ui-vue/src/router/index.ts @@ -9,6 +9,7 @@ import CaptureConfigView from '@/views/CaptureConfigView.vue' import FlashConfigView from '@/views/FlashConfigView.vue' import OtherConfigView from '@/views/OtherConfigView.vue' import LoggingConfigView from '@/views/LoggingConfigView.vue' +import AboutConfigView from '@/views/AboutConfigView.vue' const router = createRouter({ history: createMemoryHistory(), @@ -64,6 +65,11 @@ const router = createRouter({ name: 'other-config', component: OtherConfigView, }, + { + path: '/about', + name: 'about-config', + component: AboutConfigView, + }, { path: '/flash', name: 'flash-config', diff --git a/IntelPresentMon/AppCef/ipm-ui-vue/src/views/AboutConfigView.vue b/IntelPresentMon/AppCef/ipm-ui-vue/src/views/AboutConfigView.vue new file mode 100644 index 00000000..ced82ab4 --- /dev/null +++ b/IntelPresentMon/AppCef/ipm-ui-vue/src/views/AboutConfigView.vue @@ -0,0 +1,179 @@ + + + + + + + + diff --git a/IntelPresentMon/AppCef/source/DataBindAccessor.cpp b/IntelPresentMon/AppCef/source/DataBindAccessor.cpp index 0812d780..26457783 100644 --- a/IntelPresentMon/AppCef/source/DataBindAccessor.cpp +++ b/IntelPresentMon/AppCef/source/DataBindAccessor.cpp @@ -81,9 +81,14 @@ namespace p2c::client::cef } } + const util::KernelWrapper* DataBindAccessor::GetKernelWrapper() const + { + return pKernelWrapper; + } + void DataBindAccessor::ClearKernelWrapper() { std::lock_guard lk{ kernelMtx }; pKernelWrapper = nullptr; } -} \ No newline at end of file +} diff --git a/IntelPresentMon/AppCef/source/DataBindAccessor.h b/IntelPresentMon/AppCef/source/DataBindAccessor.h index ced6059f..8c926006 100644 --- a/IntelPresentMon/AppCef/source/DataBindAccessor.h +++ b/IntelPresentMon/AppCef/source/DataBindAccessor.h @@ -19,6 +19,7 @@ namespace p2c::client::cef CefRefPtr& retval, CefString& exception) override; void ResolveAsyncEndpoint(uint64_t uid, bool success, CefRefPtr pArgs); + const util::KernelWrapper* GetKernelWrapper() const; void ClearKernelWrapper(); private: // data @@ -29,4 +30,4 @@ namespace p2c::client::cef IMPLEMENT_REFCOUNTING(DataBindAccessor); friend class DBAKernelHandler; }; -} \ No newline at end of file +} diff --git a/IntelPresentMon/AppCef/source/util/ActionClientServer.cpp b/IntelPresentMon/AppCef/source/util/ActionClientServer.cpp index ebe6e1c2..f42224f1 100644 --- a/IntelPresentMon/AppCef/source/util/ActionClientServer.cpp +++ b/IntelPresentMon/AppCef/source/util/ActionClientServer.cpp @@ -8,6 +8,30 @@ namespace p2c::client::util SymmetricActionClient{ std::move(pipeName), std::move(context) } { auto res = DispatchSync(kproc::kact::OpenSession::Params{ GetCurrentProcessId() }); + serviceBuildId_ = std::move(res.serviceBuildId); + serviceBuildTime_ = std::move(res.serviceBuildTime); + serviceVersion_ = std::move(res.serviceVersion); + middlewareApiVersion_ = std::move(res.middlewareApiVersion); EstablishSession_(res.kernelPid); } -} \ No newline at end of file + + const std::string& CefClient::GetServiceBuildId() const + { + return serviceBuildId_; + } + + const std::string& CefClient::GetServiceBuildTime() const + { + return serviceBuildTime_; + } + + const std::string& CefClient::GetServiceVersion() const + { + return serviceVersion_; + } + + const std::string& CefClient::GetMiddlewareApiVersion() const + { + return middlewareApiVersion_; + } +} diff --git a/IntelPresentMon/AppCef/source/util/ActionClientServer.h b/IntelPresentMon/AppCef/source/util/ActionClientServer.h index 5ce159da..489ebb53 100644 --- a/IntelPresentMon/AppCef/source/util/ActionClientServer.h +++ b/IntelPresentMon/AppCef/source/util/ActionClientServer.h @@ -7,6 +7,16 @@ namespace p2c::client::util using namespace ::pmon::ipc; class CefClient : public act::SymmetricActionClient { - public: CefClient(std::string pipeName, cact::CefExecutionContext context = {}); + public: + CefClient(std::string pipeName, cact::CefExecutionContext context = {}); + const std::string& GetServiceBuildId() const; + const std::string& GetServiceBuildTime() const; + const std::string& GetServiceVersion() const; + const std::string& GetMiddlewareApiVersion() const; + private: + std::string serviceBuildId_; + std::string serviceBuildTime_; + std::string serviceVersion_; + std::string middlewareApiVersion_; }; -} \ No newline at end of file +} diff --git a/IntelPresentMon/AppCef/source/util/AsyncEndpointCollection.cpp b/IntelPresentMon/AppCef/source/util/AsyncEndpointCollection.cpp index 668cd560..c96b6ce3 100644 --- a/IntelPresentMon/AppCef/source/util/AsyncEndpointCollection.cpp +++ b/IntelPresentMon/AppCef/source/util/AsyncEndpointCollection.cpp @@ -16,13 +16,14 @@ #include "async/GetTopGpuProcess.h" #include "async/LoadEnvVars.h" #include "async/CheckPathExistence.h" +#include "async/GetAppInfo.h" namespace p2c::client::util { template void AsyncEndpointCollection::AddEndpoint() { - if (auto&& [i, inserted] = endpoints.insert({ T::GetKey(), std::make_unique() }); !inserted) + if (!endpoints.insert({ T::GetKey(), std::make_unique() }).second) { pmlog_warn(std::format("Duplicate key for async {}", T::GetKey())); } @@ -43,6 +44,7 @@ namespace p2c::client::util AddEndpoint(); AddEndpoint(); AddEndpoint(); + AddEndpoint(); } const AsyncEndpoint* AsyncEndpointCollection::Find(const std::string& key) const @@ -56,4 +58,4 @@ namespace p2c::client::util return nullptr; } } -} \ No newline at end of file +} diff --git a/IntelPresentMon/AppCef/source/util/async/GetAppInfo.h b/IntelPresentMon/AppCef/source/util/async/GetAppInfo.h new file mode 100644 index 00000000..61bd5a77 --- /dev/null +++ b/IntelPresentMon/AppCef/source/util/async/GetAppInfo.h @@ -0,0 +1,161 @@ +// Copyright (C) 2022 Intel Corporation +// SPDX-License-Identifier: MIT +#pragma once +#include "../AsyncEndpoint.h" +#include "../CefValues.h" +#include "../CliOptions.h" +#include "../../DataBindAccessor.h" +#include +#include +#include +#include +#include +#include +#include + +#ifndef PM_VER_PRODUCT_STR +#define PM_VER_PRODUCT_STR "unknown" +#endif + +#ifndef PM_VER_FILE_STR +#define PM_VER_FILE_STR "unknown" +#endif + +#ifndef PM_BUILD_WINSDK_VERSION_STR +#define PM_BUILD_WINSDK_VERSION_STR "unknown" +#endif + +#ifndef PM_BUILD_CRT_RUNTIME_STR +#define PM_BUILD_CRT_RUNTIME_STR "unknown" +#endif + +namespace p2c::client::util::async +{ + inline std::string FormatApiVersion_(const PM_VERSION& version) + { + auto formatted = std::format("{}.{}.{}", version.major, version.minor, version.patch); + if (version.tag[0] != '\0') { + formatted += std::format(" {}", version.tag); + } + return formatted + std::format(" {} {}", version.hash, version.config); + } + + inline std::string FormatApiHeaderVersion_() + { + return std::format("{}.{}.0", PM_API_VERSION_MAJOR, PM_API_VERSION_MINOR); + } + + inline std::string FormatCrtVersion_() + { +#if defined(_VC_CRT_MAJOR_VERSION) && defined(_VC_CRT_MINOR_VERSION) && defined(_VC_CRT_BUILD_VERSION) && defined(_VC_CRT_RBUILD_VERSION) + return std::format("{}.{}.{}.{}", + _VC_CRT_MAJOR_VERSION, + _VC_CRT_MINOR_VERSION, + _VC_CRT_BUILD_VERSION, + _VC_CRT_RBUILD_VERSION); +#elif defined(_VC_CRT_MAJOR_VERSION) && defined(_VC_CRT_MINOR_VERSION) && defined(_VC_CRT_BUILD_VERSION) + return std::format("{}.{}.{}", + _VC_CRT_MAJOR_VERSION, + _VC_CRT_MINOR_VERSION, + _VC_CRT_BUILD_VERSION); +#else + return "unknown"; +#endif + } + + inline std::string FormatCrtRuntime_() + { + constexpr std::string_view runtime{ PM_BUILD_CRT_RUNTIME_STR }; + if constexpr (runtime == "unknown") { + return "unknown"; + } + constexpr std::string_view linkType = + runtime.find("DLL") == std::string_view::npos ? "static" : "dynamic"; + return std::format("{} ({})", runtime, linkType); + } + + inline std::string FormatVerboseModules_(const cli::Options& opt) + { + if (!opt.logVerboseModules) { + return "None"; + } + + const auto& modules = *opt.logVerboseModules; + if (modules.empty()) { + return "None"; + } + + std::string formatted; + for (const auto module : modules) { + if (!formatted.empty()) { + formatted += ", "; + } + formatted += log::GetVerboseModuleName(module); + } + return formatted; + } + + class GetAppInfo : public AsyncEndpoint + { + public: + static constexpr std::string GetKey() { return "getAppInfo"; } + GetAppInfo() : AsyncEndpoint{ AsyncEndpoint::Environment::RenderProcess } {} + // {} => AppInfo + Result ExecuteOnRenderer(uint64_t uid, CefRefPtr pArgObj, cef::DataBindAccessor& accessor) const override + { + const auto& opt = cli::Options::Get(); + +#ifdef NDEBUG + constexpr bool isDebugBuild = false; +#else + constexpr bool isDebugBuild = true; +#endif + const auto pKernelWrapper = accessor.GetKernelWrapper(); + const auto pClient = pKernelWrapper ? pKernelWrapper->pClient.get() : nullptr; + + auto info = MakeCefObject( + CefProp{ "productName", std::string{ "Intel(R) PresentMon" } }, + CefProp{ "productVersion", std::string{ PM_VER_PRODUCT_STR } }, + CefProp{ "fileVersion", std::string{ PM_VER_FILE_STR } }, + CefProp{ "apiVersion", FormatApiHeaderVersion_() }, + CefProp{ "middlewareApiVersion", pClient ? pClient->GetMiddlewareApiVersion() : std::string{ "unknown" } }, + CefProp{ "buildId", std::string{ ::pmon::bid::BuildIdUid() } }, + CefProp{ "buildHash", std::string{ ::pmon::bid::BuildIdLongHash() } }, + CefProp{ "buildHashShort", std::string{ ::pmon::bid::BuildIdShortHash() } }, + CefProp{ "buildDateTime", std::string{ ::pmon::bid::BuildIdTimestamp() } }, + CefProp{ "buildConfig", std::string{ ::pmon::bid::BuildIdConfig() } }, + CefProp{ "buildDirty", ::pmon::bid::BuildIdDirtyFlag() }, + CefProp{ "isDebugBuild", isDebugBuild }, + CefProp{ "compileDate", std::string{ __DATE__ } }, + CefProp{ "compileTime", std::string{ __TIME__ } }, + CefProp{ "serviceBuildId", pClient ? pClient->GetServiceBuildId() : std::string{ "unknown" } }, + CefProp{ "serviceBuildTime", pClient ? pClient->GetServiceBuildTime() : std::string{ "unknown" } }, + CefProp{ "serviceVersion", pClient ? pClient->GetServiceVersion() : std::string{ "unknown" } }, + CefProp{ "cefVersion", std::string{ CEF_VERSION } }, + CefProp{ "cefVersionMajor", CEF_VERSION_MAJOR }, + CefProp{ "cefVersionMinor", CEF_VERSION_MINOR }, + CefProp{ "cefVersionPatch", CEF_VERSION_PATCH }, + CefProp{ "chromeVersion", std::format("{}.{}.{}.{}", + CHROME_VERSION_MAJOR, + CHROME_VERSION_MINOR, + CHROME_VERSION_BUILD, + CHROME_VERSION_PATCH) }, + CefProp{ "chromeVersionMajor", CHROME_VERSION_MAJOR }, + CefProp{ "chromeVersionMinor", CHROME_VERSION_MINOR }, + CefProp{ "chromeVersionBuild", CHROME_VERSION_BUILD }, + CefProp{ "chromeVersionPatch", CHROME_VERSION_PATCH }, + CefProp{ "cefProcessType", opt.cefType.AsOptional().value_or("browser") }, + CefProp{ "msvcVersion", std::format("{}.{} ({})", _MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER) }, + CefProp{ "winSdkVersion", std::string{ PM_BUILD_WINSDK_VERSION_STR } }, + CefProp{ "crtVersion", FormatCrtVersion_() }, + CefProp{ "crtRuntime", FormatCrtRuntime_() }, + CefProp{ "logLevel", log::GetLevelName(log::GlobalPolicy::Get().GetLogLevel()) }, + CefProp{ "verboseModules", FormatVerboseModules_(opt) }, + CefProp{ "devModeEnabled", (bool)opt.enableUiDevOptions }, + CefProp{ "debugBlocklistEnabled", (bool)opt.filesWorking }, + CefProp{ "chromiumDebugEnabled", (bool)opt.enableChromiumDebug } + ); + return Result{ true, std::move(info) }; + } + }; +} diff --git a/IntelPresentMon/KernelProcess/KernelProcess.vcxproj b/IntelPresentMon/KernelProcess/KernelProcess.vcxproj index a94c5e1f..8ae33ee8 100644 --- a/IntelPresentMon/KernelProcess/KernelProcess.vcxproj +++ b/IntelPresentMon/KernelProcess/KernelProcess.vcxproj @@ -77,7 +77,7 @@ Level3 true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _DEBUG;_CONSOLE;PM_KERNEL_PROCESS_BUILD=1;PM_VER_PRODUCT_STR="$(PresentMonProductVersion)";%(PreprocessorDefinitions) true MultiThreadedDebug stdcpplatest @@ -95,7 +95,7 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + NDEBUG;_CONSOLE;PM_KERNEL_PROCESS_BUILD=1;PM_VER_PRODUCT_STR="$(PresentMonProductVersion)";%(PreprocessorDefinitions) true MultiThreaded stdcpplatest @@ -123,7 +123,7 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + NDEBUG;_CONSOLE;PM_KERNEL_PROCESS_BUILD=1;PM_VER_PRODUCT_STR="$(PresentMonProductVersion)";%(PreprocessorDefinitions) true MultiThreaded stdcpplatest @@ -200,4 +200,4 @@ - \ No newline at end of file + diff --git a/IntelPresentMon/KernelProcess/kact/OpenSession.h b/IntelPresentMon/KernelProcess/kact/OpenSession.h index ba709ce1..71064c21 100644 --- a/IntelPresentMon/KernelProcess/kact/OpenSession.h +++ b/IntelPresentMon/KernelProcess/kact/OpenSession.h @@ -1,8 +1,17 @@ #pragma once #include "../../Interprocess/source/act/ActionHelper.h" #include "KernelExecutionContext.h" +#include #include +#ifdef PM_KERNEL_PROCESS_BUILD +#include +#endif + +#ifndef PM_VER_PRODUCT_STR +#define PM_VER_PRODUCT_STR "unknown" +#endif + #define ACT_NAME OpenSession #define ACT_EXEC_CTX KernelExecutionContext #define ACT_TYPE AsyncActionBase_ @@ -12,6 +21,26 @@ namespace ACT_NS { using namespace ::pmon::ipc::act; +#ifdef PM_KERNEL_PROCESS_BUILD + inline std::string FormatMiddlewareApiVersion_(const PM_VERSION& version) + { + auto formatted = std::format("{}.{}.{}", version.major, version.minor, version.patch); + if (version.tag[0] != '\0') { + formatted += std::format(" {}", version.tag); + } + return formatted + std::format(" {} {}", version.hash, version.config); + } + + inline std::string GetMiddlewareApiVersion_() + { + PM_VERSION version{}; + if (pmGetApiVersion(&version) != PM_STATUS_SUCCESS) { + return "unknown"; + } + return FormatMiddlewareApiVersion_(version); + } +#endif + class ACT_NAME : public ACT_TYPE { public: @@ -26,9 +55,13 @@ namespace ACT_NS }; struct Response { uint32_t kernelPid; + std::string serviceBuildId; + std::string serviceBuildTime; + std::string serviceVersion; + std::string middlewareApiVersion; template void serialize(A& ar) { - ar(kernelPid); + ar(kernelPid, serviceBuildId, serviceBuildTime, serviceVersion, middlewareApiVersion); } }; private: @@ -36,7 +69,17 @@ namespace ACT_NS static Response Execute_(const ACT_EXEC_CTX& ctx, SessionContext& stx, Params&& in) { stx.remotePid = in.cefRenderPid; - const Response res{ .kernelPid = GetCurrentProcessId() }; + const Response res{ + .kernelPid = GetCurrentProcessId(), + .serviceBuildId = ::pmon::bid::BuildIdLongHash(), + .serviceBuildTime = ::pmon::bid::BuildIdTimestamp(), + .serviceVersion = PM_VER_PRODUCT_STR, +#ifdef PM_KERNEL_PROCESS_BUILD + .middlewareApiVersion = GetMiddlewareApiVersion_(), +#else + .middlewareApiVersion = "unknown", +#endif + }; pmlog_info(std::format("Kernel open action for cef={} krn={}", in.cefRenderPid, res.kernelPid)); return res; } @@ -50,4 +93,4 @@ ACTION_TRAITS_DEF(); #undef ACT_NAME #undef ACT_EXEC_CTX #undef ACT_NS -#undef ACT_TYPE \ No newline at end of file +#undef ACT_TYPE diff --git a/IntelPresentMon/PresentMonMiddleware/ActionClient.h b/IntelPresentMon/PresentMonMiddleware/ActionClient.h index b12c28ef..d96379f8 100644 --- a/IntelPresentMon/PresentMonMiddleware/ActionClient.h +++ b/IntelPresentMon/PresentMonMiddleware/ActionClient.h @@ -39,12 +39,12 @@ namespace pmon::mid { auto res = DispatchSync(OpenSession::Params{ .clientPid = GetCurrentProcessId(), - .clientBuildId = bid::BuildIdShortHash(), + .clientBuildId = bid::BuildIdLongHash(), .clientBuildConfig = bid::BuildIdConfig(), }); - if (res.serviceBuildId != bid::BuildIdShortHash()) { + if (res.serviceBuildId != bid::BuildIdLongHash()) { pmlog_error("build id mismatch between middleware and service") - .pmwatch(res.serviceBuildId).pmwatch(bid::BuildIdShortHash()).diag(); + .pmwatch(res.serviceBuildId).pmwatch(bid::BuildIdLongHash()).diag(); throw Except(PM_STATUS_MIDDLEWARE_SERVICE_MISMATCH); } if (res.serviceBuildConfig != bid::BuildIdConfig()) { diff --git a/IntelPresentMon/PresentMonService/PresentMonService.vcxproj b/IntelPresentMon/PresentMonService/PresentMonService.vcxproj index 85bc9a54..f7ea75fe 100644 --- a/IntelPresentMon/PresentMonService/PresentMonService.vcxproj +++ b/IntelPresentMon/PresentMonService/PresentMonService.vcxproj @@ -68,6 +68,7 @@ Level3 true + PM_VER_PRODUCT_STR="$(PresentMonProductVersion)";%(PreprocessorDefinitions) true MultiThreadedDebug EditAndContinue @@ -96,7 +97,7 @@ MultiThreaded MaxSpeed stdcpplatest - NDEBUG;%(PreprocessorDefinitions) + NDEBUG;PM_VER_PRODUCT_STR="$(PresentMonProductVersion)";%(PreprocessorDefinitions) Guard diff --git a/IntelPresentMon/PresentMonService/acts/OpenSession.h b/IntelPresentMon/PresentMonService/acts/OpenSession.h index 9ccd3a1e..56d8693c 100644 --- a/IntelPresentMon/PresentMonService/acts/OpenSession.h +++ b/IntelPresentMon/PresentMonService/acts/OpenSession.h @@ -4,6 +4,10 @@ #include "../../Versioning/BuildId.h" #include +#ifndef PM_VER_PRODUCT_STR +#define PM_VER_PRODUCT_STR "unknown" +#endif + #define ACT_NAME OpenSession #define ACT_EXEC_CTX ActionExecutionContext #define ACT_TYPE AsyncActionBase_ @@ -30,12 +34,14 @@ namespace pmon::svc::acts struct Response { uint32_t servicePid; std::string serviceBuildId; + std::string serviceBuildTime; + std::string serviceVersion; std::string serviceBuildConfig; std::string shmPrefix; std::string shmSalt; template void serialize(A& ar) { - ar(servicePid, serviceBuildId, serviceBuildConfig, shmPrefix, shmSalt); + ar(servicePid, serviceBuildId, serviceBuildTime, serviceVersion, serviceBuildConfig, shmPrefix, shmSalt); } }; private: @@ -46,11 +52,13 @@ namespace pmon::svc::acts stx.clientBuildId = in.clientBuildId; ctx.pSvc->SignalClientSessionOpened(); pmlog_info(std::format("Open action for session #{} pid={}; [BID] cli={} svc={} [CFG] cli={} svc={}", - stx.pConn->GetId(), in.clientPid, in.clientBuildId, bid::BuildIdShortHash(), + stx.pConn->GetId(), in.clientPid, in.clientBuildId, bid::BuildIdLongHash(), in.clientBuildConfig, bid::BuildIdConfig())); return Response{ .servicePid = GetCurrentProcessId(), - .serviceBuildId = bid::BuildIdShortHash(), + .serviceBuildId = bid::BuildIdLongHash(), + .serviceBuildTime = bid::BuildIdTimestamp(), + .serviceVersion = PM_VER_PRODUCT_STR, .serviceBuildConfig = bid::BuildIdConfig(), .shmPrefix = ctx.pPmon->GetBroadcaster().GetNamer().GetPrefix(), .shmSalt = ctx.pPmon->GetBroadcaster().GetNamer().GetSalt(),