Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions IntelPresentMon/AppCef/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ add_executable(
source/util/FontEnumerator.cpp
source/util/IpcInvocationManager.cpp
source/util/KernelActionRegistration.cpp
source/util/KernelLink.cpp
source/util/KernelRelay.cpp
source/util/LogSetup.cpp
source/util/PathSanitaryCheck.cpp
source/util/SignalManager.cpp
Expand Down
4 changes: 4 additions & 0 deletions IntelPresentMon/AppCef/CefNano.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
<ClCompile Include="source\util\FontEnumerator.cpp" />
<ClCompile Include="source\util\IpcInvocationManager.cpp" />
<ClCompile Include="source\util\KernelActionRegistration.cpp" />
<ClCompile Include="source\util\KernelLink.cpp" />
<ClCompile Include="source\util\KernelRelay.cpp" />
<ClCompile Include="source\util\LogSetup.cpp" />
<ClCompile Include="source\util\PathSanitaryCheck.cpp" />
<ClCompile Include="source\util\SignalManager.cpp" />
Expand Down Expand Up @@ -52,6 +54,8 @@
<ClInclude Include="source\util\CefLog.h" />
<ClInclude Include="source\util\CliOptions.h" />
<ClInclude Include="source\util\IpcInvocationManager.h" />
<ClInclude Include="source\util\KernelLink.h" />
<ClInclude Include="source\util\KernelRelay.h" />
<ClInclude Include="source\util\AsyncEndpoint.h" />
<ClInclude Include="source\util\AsyncEndpointCollection.h" />
<ClInclude Include="source\util\AsyncEndpointManager.h" />
Expand Down
10 changes: 0 additions & 10 deletions IntelPresentMon/AppCef/source/DataBindAccessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@
// SPDX-License-Identifier: MIT
#include "DataBindAccessor.h"
#include "util/Logging.h"
#include <include/cef_task.h>
#include <include/base/cef_callback.h>
#include <include/wrapper/cef_closure_task.h>
#include "util/CefValues.h"
#include <Interprocess/source/act/SymmetricActionServer.h>
#include "util/cact/TargetLostAction.h"
#include "util/cact/OverlayDiedAction.h"
#include "util/cact/PresentmonInitFailedAction.h"
#include "util/cact/StalePidAction.h"
#include "util/SignalManager.h"


namespace p2c::client::cef
Expand Down
9 changes: 9 additions & 0 deletions IntelPresentMon/AppCef/source/NanoCefBrowserClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <streambuf>
#include "util/AsyncEndpointManager.h"
#include "NanoCefProcessHandler.h"
#include "util/KernelRelay.h"

// implemented in winmain.cpp
void AppQuitMessageLoop();
Expand Down Expand Up @@ -35,6 +36,11 @@ namespace p2c::client::cef
pContextMenuHandler = new NullMenuHandler{};
}

void NanoCefBrowserClient::SetKernelCallRelay(util::kernel_relay::CallRelay* pRelay)
{
pKernelCallRelay = pRelay;
}

CefRefPtr<CefBrowser> NanoCefBrowserClient::GetBrowser()
{
return pBrowser;
Expand Down Expand Up @@ -66,6 +72,9 @@ namespace p2c::client::cef

bool NanoCefBrowserClient::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefProcessId source_process, CefRefPtr<CefProcessMessage> message)
{
if (pKernelCallRelay && pKernelCallRelay->HandleMessage(*message, frame)) {
return true;
}
if (message->GetName() == util::AsyncEndpointManager::GetDispatchMessageName())
{
if (auto pEndpoint = endpoints.Find(message->GetArgumentList()->GetString(0)))
Expand Down
8 changes: 8 additions & 0 deletions IntelPresentMon/AppCef/source/NanoCefBrowserClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
#include <optional>
#include "util/AsyncEndpointCollection.h"

namespace p2c::client::util::kernel_relay
{
class CallRelay;
}

namespace p2c::client::cef
{
Expand All @@ -18,6 +22,9 @@ namespace p2c::client::cef
{
public:
NanoCefBrowserClient();
// Kernel calls from the page are handed to this relay. Set before the browser is created,
// since only the page sends them; null leaves them unhandled.
void SetKernelCallRelay(util::kernel_relay::CallRelay* pRelay);
CefRefPtr<CefBrowser> GetBrowser();
CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override;
CefRefPtr<CefDisplayHandler> GetDisplayHandler() override;
Expand All @@ -40,6 +47,7 @@ namespace p2c::client::cef
CefRefPtr<CefContextMenuHandler> pContextMenuHandler;
CefRefPtr<CefBrowser> pBrowser;
util::AsyncEndpointCollection endpoints;
util::kernel_relay::CallRelay* pKernelCallRelay = nullptr;

// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(NanoCefBrowserClient);
Expand Down
49 changes: 43 additions & 6 deletions IntelPresentMon/AppCef/source/NanoCefProcessHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,26 @@
#include "util/AsyncEndpointManager.h"
#include "util/CefValues.h"
#include "util/CliOptions.h"
#include "util/KernelRelay.h"
#include <CommonUtilities/win/Privileges.h>

using namespace pmon::util;
using namespace std::chrono_literals;
namespace rn = std::ranges;
namespace vi = std::views;

namespace p2c::client::cef
{
void NanoCefProcessHandler::OnBeforeCommandLineProcessing(const CefString& processType, CefRefPtr<CefCommandLine> pCommandLine)
{
// An elevated kernel launches the UI at medium integrity with a token restricted from its
// own. Chromium reads that token as elevated, relaunches itself without the kernel pipe,
// and exits. Opt out only when we really are below high integrity, so a UI that did run
// elevated is still de-elevated by Chromium.
if (processType.empty() && ::pmon::util::win::WeAreBelowHighIntegrity()) {
pCommandLine->AppendSwitch("do-not-de-elevate");
}
}

void NanoCefProcessHandler::OnContextInitialized()
{
#ifdef NDEBUG
Expand Down Expand Up @@ -112,11 +124,14 @@ namespace p2c::client::cef

void NanoCefProcessHandler::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
std::this_thread::sleep_for(50ms);
pKernelWrapper->pClient = std::make_unique<util::CefClient>(
*util::cli::Options::Get().actName, util::cact::CefExecutionContext{.pSignalManager = &pKernelWrapper->signals}
);
pKernelWrapper->pInvocationManager = std::make_unique<util::IpcInvocationManager>(*pKernelWrapper->pClient);
// Only the main frame gets the kernel bridge. A subframe's context must not replace the
// invocation manager, which would drop the main frame's pending calls, and it has no
// business calling the kernel. A main-frame reload does start fresh: its old page is gone.
if (!frame->IsMain()) {
return;
}
// kernel calls are relayed through the browser process, which holds the kernel connection
pKernelWrapper->pInvocationManager = std::make_unique<util::IpcInvocationManager>();
Comment thread
Copilot marked this conversation as resolved.
pAccessor = new DataBindAccessor{ pBrowser, pKernelWrapper.get() };

auto core = CefV8Value::CreateObject(nullptr, nullptr);
Expand All @@ -138,11 +153,33 @@ namespace p2c::client::cef

pBrowser = browser_;

// versions the kernel reported to the browser process when it opened its session
if (extra_info) {
namespace kr = util::kernel_relay;
auto& versions = pKernelWrapper->kernelVersions;
versions.serviceBuildId = extra_info->GetString(kr::kServiceBuildIdKey).ToString();
versions.serviceBuildTime = extra_info->GetString(kr::kServiceBuildTimeKey).ToString();
versions.serviceVersion = extra_info->GetString(kr::kServiceVersionKey).ToString();
versions.middlewareApiVersion = extra_info->GetString(kr::kMiddlewareApiVersionKey).ToString();
}

CefRenderProcessHandler::OnBrowserCreated(std::move(browser_), std::move(extra_info));
}

bool NanoCefProcessHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefProcessId source_process, CefRefPtr<CefProcessMessage> message)
{
if (pKernelWrapper->pInvocationManager && pKernelWrapper->pInvocationManager->HandleReply(*message)) {
return true;
}
if (message->GetName() == util::kernel_relay::kSignalMessage) {
const auto args = message->GetArgumentList();
std::optional<uint32_t> arg;
if (args->GetType(1) == VTYPE_INT) {
arg = (uint32_t)args->GetInt(1);
}
pKernelWrapper->signals.SignalFromBrowser(args->GetString(0).ToString(), arg);
return true;
}
if (message->GetName() == util::AsyncEndpointManager::GetResolveMessageName())
{
pAccessor->ResolveAsyncEndpoint(
Expand Down
1 change: 1 addition & 0 deletions IntelPresentMon/AppCef/source/NanoCefProcessHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace p2c::client::cef
public CefBrowserProcessHandler
{
public:
void OnBeforeCommandLineProcessing(const CefString& processType, CefRefPtr<CefCommandLine> pCommandLine) override;
void OnContextInitialized() override;
CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override;
CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override;
Expand Down
4 changes: 2 additions & 2 deletions IntelPresentMon/AppCef/source/util/ActionClientServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

namespace p2c::client::util
{
CefClient::CefClient(std::string pipeName, cact::CefExecutionContext context)
CefClient::CefClient(::pmon::util::win::Handle connectedPipe, cact::CefExecutionContext context)
:
SymmetricActionClient{ std::move(pipeName), std::move(context) }
SymmetricActionClient{ std::move(connectedPipe), "kernel-ui", std::move(context) }
{
auto res = DispatchSync(kproc::kact::OpenSession::Params{ GetCurrentProcessId() });
serviceBuildId_ = std::move(res.serviceBuildId);
Expand Down
3 changes: 2 additions & 1 deletion IntelPresentMon/AppCef/source/util/ActionClientServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ namespace p2c::client::util

class CefClient : public act::SymmetricActionClient<cact::CefExecutionContext> {
public:
CefClient(std::string pipeName, cact::CefExecutionContext context = {});
// connectedPipe: the client end of the pipe pair the kernel created for this UI
CefClient(::pmon::util::win::Handle connectedPipe, cact::CefExecutionContext context);
const std::string& GetServiceBuildId() const;
const std::string& GetServiceBuildTime() const;
const std::string& GetServiceVersion() const;
Expand Down
5 changes: 3 additions & 2 deletions IntelPresentMon/AppCef/source/util/CliOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,15 @@ namespace p2c::client::util::cli
private: Group gi_{ this, "Internal", "Internal options, do not supply manually" }; public:
Option<std::string> cefType{ this, "--type", "", "Type of the current chromium process" };
Option<std::string> logPipeName{ this, "--p2c-log-pipe-name", "", "The postfix used to create the named pipe for logging source server" };
Option<std::string> actName{ this, "--p2c-act-name", "", "Base name for the named pipes connecting CEF and the overlay Kernel process" };
Option<uint64_t> actHandle{ this, "--p2c-act-handle", 0, "Inherited handle of the pipe connecting CEF and the overlay Kernel process" };

static constexpr const char* description = "PresentMon control UI";
static constexpr const char* name = "PresentMonUI.exe";

private:
MutualExclusion excl_{ logDenyList, logAllowList };
NoForward noForward_{ cefType, logPipeName, logVerboseModules };
// actHandle is meaningful only in the browser process that inherited it
NoForward noForward_{ cefType, logPipeName, logVerboseModules, actHandle };
AllowExtras ext_{ this };
};
}
41 changes: 39 additions & 2 deletions IntelPresentMon/AppCef/source/util/IpcInvocationManager.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,46 @@
#pragma once
#include "IpcInvocationManager.h"


namespace p2c::client::util
{
std::unordered_map<std::string, std::function<void(IpcInvocationManager::CallbackContext, CefRefPtr<CefV8Value>, CefClient&)>>
std::unordered_map<std::string, std::function<void(IpcInvocationManager&, IpcInvocationManager::CallbackContext, CefRefPtr<CefV8Value>)>>
IpcInvocationManager::dispatchBindings_;
int IpcInvocationManager::nextCallId_ = 0;

bool IpcInvocationManager::HandleReply(CefProcessMessage& message)
{
CEF_REQUIRE_RENDERER_THREAD();
if (message.GetName() != kernel_relay::kReplyMessage) {
return false;
}
const auto args = message.GetArgumentList();
const auto callId = args->GetInt(0);
const auto i = pendingCalls_.find(callId);
if (i == pendingCalls_.end()) {
pmlog_dbg("Dropping kernel call reply for an unknown call").pmwatch(callId);
return true;
}
auto onReply = std::move(i->second);
pendingCalls_.erase(i);
// no binary value means the Response serialized to no bytes
onReply(args->GetBool(1), args->GetType(2) == VTYPE_BINARY ? args->GetBinary(2) : nullptr);
return true;
}

void IpcInvocationManager::SendCall_(const std::string& action, CefRefPtr<CefBinaryValue> pParams,
CefRefPtr<CefFrame> frame, ReplyHandler onReply)
{
CEF_REQUIRE_RENDERER_THREAD();
const auto callId = nextCallId_++;
auto message = CefProcessMessage::Create(kernel_relay::kCallMessage);
const auto args = message->GetArgumentList();
args->SetString(0, action);
args->SetInt(1, callId);
// null when Params serialized to no bytes, see kernel_relay::ToBinary
if (pParams) {
args->SetBinary(2, std::move(pParams));
}
pendingCalls_.emplace(callId, std::move(onReply));
frame->SendProcessMessage(PID_BROWSER, std::move(message));
}
}
Loading
Loading