blob: 0974891a03a5d43dee927ebcb17f99b8d74dd6d0 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <windows.h>
#include <utility>
#include "base/at_exit.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/process/memory.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/single_thread_task_executor.h"
#include "base/threading/thread.h"
#include "base/win/process_startup_helper.h"
#include "base/win/scoped_com_initializer.h"
#include "chrome/test/accessibility/ax_client/ax_client.h"
#include "chrome/test/accessibility/ax_client/ax_client.test-mojom-forward.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/core/embedder/scoped_ipc_support.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace {
ax_client::AxClient::ClientApi GetClientApi(
const base::CommandLine& command_line) {
int value;
if (auto value_str = command_line.GetSwitchValueNative("client-api");
base::StringToInt(value_str, &value)) {
switch (value) {
case static_cast<int>(ax_client::AxClient::ClientApi::kUiAutomation):
return ax_client::AxClient::ClientApi::kUiAutomation;
case static_cast<int>(ax_client::AxClient::ClientApi::kIAccessible2):
return ax_client::AxClient::ClientApi::kIAccessible2;
default:
NOTREACHED() << "--client-api=" << value << " out of bounds";
}
} else {
NOTREACHED() << "--client-api=" << value_str << " invalid";
}
}
} // namespace
extern "C" int wmain(int argc, const wchar_t* const argv) {
base::AtExitManager at_exit;
base::CommandLine::Init(/*argc=*/0, /*argv=*/nullptr);
auto& command_line = *base::CommandLine::ForCurrentProcess();
logging::InitLogging({.logging_dest = logging::LOG_TO_STDERR});
logging::SetLogItems(/*enable_process_id=*/true,
/*enable_thread_id=*/true,
/*enable_timestamp=*/true,
/*enable_tickcount=*/false);
// Make sure the process exits cleanly on unexpected errors.
base::EnableTerminationOnHeapCorruption();
base::EnableTerminationOnOutOfMemory();
logging::RegisterAbslAbortHook();
base::win::RegisterInvalidParamHandler();
base::win::SetupCRT(command_line);
const ax_client::AxClient::ClientApi client_api = GetClientApi(command_line);
// Basic Mojo initialization for a new process.
mojo::core::Init();
base::Thread ipc_thread("ipc");
ipc_thread.StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0));
mojo::core::ScopedIPCSupport ipc_support(
ipc_thread.task_runner(),
mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST);
// Accept the invitation for the AxClient instance.
mojo::IncomingInvitation invitation = mojo::IncomingInvitation::Accept(
mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(
command_line));
mojo::ScopedMessagePipeHandle pipe =
invitation.ExtractMessagePipe(/*name=*/0);
// Initialize COM on this main thread.
std::optional<base::win::ScopedCOMInitializer> com_initializer;
switch (client_api) {
case ax_client::AxClient::ClientApi::kUiAutomation:
// MTA for UI Automation.
com_initializer.emplace(base::win::ScopedCOMInitializer::kMTA);
break;
case ax_client::AxClient::ClientApi::kIAccessible2:
// STA for MSAA/IA2.
com_initializer.emplace();
break;
}
CHECK(com_initializer->Succeeded());
// Run a task executor on this main thread -- it will host the AxClient.
// MSAA/IA2 requires a UI message pump since this thread hosts the client's
// WinEvent hook.
base::SingleThreadTaskExecutor task_executor(
client_api == ax_client::AxClient::ClientApi::kIAccessible2
? base::MessagePumpType::UI
: base::MessagePumpType::DEFAULT,
/*is_main_thread=*/true);
base::RunLoop run_loop;
// Create and bind the client such that the RunLoop quits upon disconnect.
mojo::MakeSelfOwnedReceiver(
std::make_unique<ax_client::AxClient>(client_api, run_loop.QuitClosure()),
mojo::PendingReceiver<ax_client::mojom::AxClient>(std::move(pipe)));
run_loop.Run();
return 0;
}