Commit 62d23080 authored by Zijie He's avatar Zijie He Committed by Commit Bot

Implement EvaluateCapability and its tests

This change adds --type=evaluate_capability command line parameter to execute
host binary in "evaluate capability" mode. Meanwhile a helper function
int EvaluateCapabilityForkedly() has been added to execute the host binary to
evaluate certain functionality, and retrieves its output.

Return value is too simple for the evaluation, e.g. for DirectX capturer, both
initialization result and DirectX version are required. To make it simple, in a
coming change, we can directly output the host attributes regarding to the
DirectX capturer into console, so the network process needs not to execute any
DirectX related logic.

Bug: 741926
Change-Id: Ief06bed7b9297318bd387106108eccd02180e066
Reviewed-on: https://chromium-review.googlesource.com/575730
Commit-Queue: Zijie He <zijiehe@chromium.org>
Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#490121}
parent 253392e5
...@@ -135,6 +135,8 @@ static_library("host") { ...@@ -135,6 +135,8 @@ static_library("host") {
"disconnect_window_win.cc", "disconnect_window_win.cc",
"dns_blackhole_checker.cc", "dns_blackhole_checker.cc",
"dns_blackhole_checker.h", "dns_blackhole_checker.h",
"evaluate_capability.cc",
"evaluate_capability.h",
"forward_process_stats_agent.cc", "forward_process_stats_agent.cc",
"forward_process_stats_agent.h", "forward_process_stats_agent.h",
"gcd_rest_client.cc", "gcd_rest_client.cc",
...@@ -532,6 +534,20 @@ source_set("unit_tests") { ...@@ -532,6 +534,20 @@ source_set("unit_tests") {
if (!is_ios) { if (!is_ios) {
deps += [ "//components/policy/core/browser:test_support" ] deps += [ "//components/policy/core/browser:test_support" ]
} }
if (enable_me2me_host) {
sources += [
"evaluate_capability_unittest.cc",
]
if (is_win) {
data_deps = [ "//remoting/host/win:remoting_me2me_host" ]
} else if (is_mac) {
data_deps = [ "//remoting/host/mac:remoting_me2me_host" ]
} else {
data_deps = [ ":remoting_me2me_host" ]
}
}
} }
group("remoting_host_branded") { group("remoting_host_branded") {
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "remoting/host/ipc_constants.h" #include "remoting/host/ipc_constants.h"
#include "remoting/host/pairing_registry_delegate_win.h" #include "remoting/host/pairing_registry_delegate_win.h"
#include "remoting/host/screen_resolution.h" #include "remoting/host/screen_resolution.h"
#include "remoting/host/switches.h"
#include "remoting/host/win/launch_process_with_token.h" #include "remoting/host/win/launch_process_with_token.h"
#include "remoting/host/win/security_descriptor.h" #include "remoting/host/win/security_descriptor.h"
#include "remoting/host/win/unprivileged_process_delegate.h" #include "remoting/host/win/unprivileged_process_delegate.h"
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "remoting/host/ipc_constants.h" #include "remoting/host/ipc_constants.h"
#include "remoting/host/sas_injector.h" #include "remoting/host/sas_injector.h"
#include "remoting/host/screen_resolution.h" #include "remoting/host/screen_resolution.h"
#include "remoting/host/switches.h"
// MIDL-generated declarations and definitions. // MIDL-generated declarations and definitions.
#include "remoting/host/win/chromoting_lib.h" #include "remoting/host/win/chromoting_lib.h"
#include "remoting/host/win/host_service.h" #include "remoting/host/win/host_service.h"
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/evaluate_capability.h"
#include <iostream>
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "build/build_config.h"
#include "remoting/host/host_exit_codes.h"
#include "remoting/host/ipc_constants.h"
#include "remoting/host/switches.h"
namespace remoting {
namespace {
// TODO(zijiehe): Move these test specific handlers into test binary.
// This function is for test purpose only. It writes some random texts to both
// stdout and stderr, and returns a random value 234.
int EvaluateTest() {
std::cout << "In EvaluateTest(): Line 1\n"
"In EvaluateTest(): Line 2";
std::cerr << "In EvaluateTest(): Error Line 1\n"
"In EvaluateTest(): Error Line 2";
return 234;
}
// This function is for test purpose only. It triggers an assertion failure.
int EvaluateCrash() {
NOTREACHED();
return 0;
}
// This function is for test purpose only. It forwards the evaluation request to
// a new process and returns what it returns.
int EvaluateForward() {
std::string output;
int result = EvaluateCapability(kEvaluateTest, &output);
std::cout << output;
return result;
}
// Returns the full path of the binary file we should use to evaluate the
// capability. According to the platform and executing environment, return of
// this function may vary. But in one process, the return value is guaranteed to
// be the same.
// This function tries to use current binary if supported, otherwise it falls
// back to use the default binary.
base::FilePath BuildHostBinaryPath() {
#if defined(OS_LINUX)
base::FilePath path;
bool result = base::PathService::Get(base::FILE_EXE, &path);
DCHECK(result);
if (path.BaseName().value() ==
FILE_PATH_LITERAL("chrome-remote-desktop-host")) {
return path;
}
if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_me2me_host")) {
return path;
}
result = base::PathService::Get(base::DIR_EXE, &path);
DCHECK(result);
return path.Append(FILE_PATH_LITERAL("remoting_me2me_host"));
#elif defined(OS_MACOSX)
base::FilePath path;
bool result = base::PathService::Get(base::FILE_EXE, &path);
DCHECK(result);
if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_me2me_host")) {
return path;
}
result = base::PathService::Get(base::DIR_EXE, &path);
DCHECK(result);
return path.Append(FILE_PATH_LITERAL(
"remoting_me2me_host.app/Contents/MacOS/remoting_me2me_host"));
#elif defined(OS_WIN)
base::FilePath path;
bool result = base::PathService::Get(base::FILE_EXE, &path);
DCHECK(result);
if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_console.exe")) {
return path;
}
if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_desktop.exe")) {
return path;
}
if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_host.exe")) {
return path;
}
result = base::PathService::Get(base::DIR_EXE, &path);
DCHECK(result);
return path.Append(FILE_PATH_LITERAL("remoting_host.exe"));
#else
#error "BuildHostBinaryPath is not implemented for current platform."
#endif
}
} // namespace
int EvaluateCapabilityLocally(const std::string& type) {
// TODO(zijiehe): Move these test specific handlers into test binary.
if (type == kEvaluateTest) {
return EvaluateTest();
}
if (type == kEvaluateCrash) {
return EvaluateCrash();
}
if (type == kEvaluateForward) {
return EvaluateForward();
}
return kInvalidCommandLineExitCode;
}
int EvaluateCapability(const std::string& type,
std::string* output /* = nullptr */) {
base::CommandLine command(BuildHostBinaryPath());
command.AppendSwitchASCII(kProcessTypeSwitchName,
kProcessTypeEvaluateCapability);
command.AppendSwitchASCII(kEvaluateCapabilitySwitchName, type);
int exit_code;
std::string dummy_output;
if (!output) {
output = &dummy_output;
}
// base::GetAppOutputWithExitCode() usually returns false when receiving
// "unknown" exit code. But we forward the |exit_code| through return value,
// so the return of base::GetAppOutputWithExitCode() should be ignored.
base::GetAppOutputWithExitCode(command, output, &exit_code);
return exit_code;
}
} // namespace remoting
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_HOST_EVALUATE_CAPABILITY_H_
#define REMOTING_HOST_EVALUATE_CAPABILITY_H_
#include <string>
namespace remoting {
// Evaluates the host capability in current process. This function should only
// be called in HostMain(), which consumes a --type=evaluate command line
// parameter. Note, this function may execute some experimental features and
// crash the process.
int EvaluateCapabilityLocally(const std::string& type);
// Evaluates the host capability in a different process and returns its exit
// code. If |output| is provided, it will be set to the stdout of the process.
// If the process failed to be started, though usually this should not happen,
// it returns TERMINATION_STATUS_LAUNCH_FAILED.
// Note, this is a blocking call. Depending on the platform and system load, it
// may take a noticeable amount of time to complete.
int EvaluateCapability(const std::string& type, std::string* output = nullptr);
} // namespace remoting
#endif // REMOTING_HOST_EVALUATE_CAPABILITY_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/evaluate_capability.h"
#include "base/strings/string_util.h"
#include "remoting/host/switches.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace remoting {
TEST(EvaluateCapabilityTest, ShouldReturnCrashResult) {
ASSERT_NE(EvaluateCapability(kEvaluateCrash), 0);
}
TEST(EvaluateCapabilityTest, ShouldReturnExitCodeAndOutput) {
std::string output;
ASSERT_EQ(EvaluateCapability(kEvaluateTest, &output), 234);
// New line character varies on different platform, so normalize the output
// here.
base::ReplaceSubstringsAfterOffset(&output, 0, "\r\n", "\n");
base::ReplaceSubstringsAfterOffset(&output, 0, "\r", "\n");
ASSERT_EQ("In EvaluateTest(): Line 1\n"
"In EvaluateTest(): Line 2",
output);
}
TEST(EvaluateCapabilityTest, ShouldForwardExitCodeAndOutput) {
std::string output;
ASSERT_EQ(EvaluateCapability(kEvaluateForward, &output), 234);
// New line character varies on different platform, so normalize the output
// here.
base::ReplaceSubstringsAfterOffset(&output, 0, "\r\n", "\n");
base::ReplaceSubstringsAfterOffset(&output, 0, "\r", "\n");
// Windows (evilly) use \r\n to replace \n, so we will end up with two \n.
base::ReplaceSubstringsAfterOffset(&output, 0, "\n\n", "\n");
ASSERT_EQ("In EvaluateTest(): Line 1\n"
"In EvaluateTest(): Line 2",
output);
}
} // namespace remoting
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "mojo/edk/embedder/embedder.h" #include "mojo/edk/embedder/embedder.h"
#include "remoting/base/breakpad.h" #include "remoting/base/breakpad.h"
#include "remoting/host/evaluate_capability.h"
#include "remoting/host/host_exit_codes.h" #include "remoting/host/host_exit_codes.h"
#include "remoting/host/logging.h" #include "remoting/host/logging.h"
#include "remoting/host/resources.h" #include "remoting/host/resources.h"
...@@ -60,11 +61,12 @@ const char kUsageMessage[] = ...@@ -60,11 +61,12 @@ const char kUsageMessage[] =
" --daemon-pipe=<pipe> - Specifies the pipe to connect to the daemon.\n" " --daemon-pipe=<pipe> - Specifies the pipe to connect to the daemon.\n"
" --elevate=<binary> - Runs <binary> elevated.\n" " --elevate=<binary> - Runs <binary> elevated.\n"
" --host-config=<config> - Specifies the host configuration.\n" " --host-config=<config> - Specifies the host configuration.\n"
" --help, -? - Print this message.\n" " --help, -? - Prints this message.\n"
" --type - Specifies process type.\n" " --type - Specifies process type.\n"
" --version - Prints the host version and exits.\n" " --version - Prints the host version and exits.\n"
" --window-id=<id> - Specifies a window to remote," " --window-id=<id> - Specifies a window to remote,"
" instead of the whole desktop.\n"; " instead of the whole desktop.\n"
" --evaluate-type=<type> - Evaluates the capability of the host.\n";
void Usage(const base::FilePath& program_name) { void Usage(const base::FilePath& program_name) {
printf(kUsageMessage, program_name.MaybeAsASCII().c_str()); printf(kUsageMessage, program_name.MaybeAsASCII().c_str());
...@@ -148,30 +150,6 @@ int HostMain(int argc, char** argv) { ...@@ -148,30 +150,6 @@ int HostMain(int argc, char** argv) {
base::CommandLine::Init(argc, argv); base::CommandLine::Init(argc, argv);
// This object instance is required by Chrome code (for example,
// LazyInstance, MessageLoop).
base::AtExitManager exit_manager;
// Enable debug logs.
InitHostLogging();
#if defined(REMOTING_ENABLE_BREAKPAD)
// Initialize Breakpad as early as possible. On Mac the command-line needs to
// be initialized first, so that the preference for crash-reporting can be
// looked up in the config file.
if (IsUsageStatsAllowed()) {
InitializeCrashReporting();
}
#endif // defined(REMOTING_ENABLE_BREAKPAD)
#if defined(OS_WIN)
// Register and initialize common controls.
INITCOMMONCONTROLSEX info;
info.dwSize = sizeof(info);
info.dwICC = ICC_STANDARD_CLASSES;
InitCommonControlsEx(&info);
#endif // defined(OS_WIN)
// Parse the command line. // Parse the command line.
const base::CommandLine* command_line = const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess(); base::CommandLine::ForCurrentProcess();
...@@ -198,6 +176,39 @@ int HostMain(int argc, char** argv) { ...@@ -198,6 +176,39 @@ int HostMain(int argc, char** argv) {
process_type = command_line->GetSwitchValueASCII(kProcessTypeSwitchName); process_type = command_line->GetSwitchValueASCII(kProcessTypeSwitchName);
} }
if (process_type == kProcessTypeEvaluateCapability) {
if (command_line->HasSwitch(kEvaluateCapabilitySwitchName)) {
return EvaluateCapabilityLocally(
command_line->GetSwitchValueASCII(kEvaluateCapabilitySwitchName));
}
Usage(command_line->GetProgram());
return kSuccessExitCode;
}
// This object instance is required by Chrome code (for example,
// LazyInstance, MessageLoop).
base::AtExitManager exit_manager;
// Enable debug logs.
InitHostLogging();
#if defined(REMOTING_ENABLE_BREAKPAD)
// Initialize Breakpad as early as possible. On Mac the command-line needs to
// be initialized first, so that the preference for crash-reporting can be
// looked up in the config file.
if (IsUsageStatsAllowed()) {
InitializeCrashReporting();
}
#endif // defined(REMOTING_ENABLE_BREAKPAD)
#if defined(OS_WIN)
// Register and initialize common controls.
INITCOMMONCONTROLSEX info;
info.dwSize = sizeof(info);
info.dwICC = ICC_STANDARD_CLASSES;
InitCommonControlsEx(&info);
#endif // defined(OS_WIN)
MainRoutineFn main_routine = SelectMainRoutine(process_type); MainRoutineFn main_routine = SelectMainRoutine(process_type);
if (!main_routine) { if (!main_routine) {
fprintf(stderr, "Unknown process type '%s' specified.", fprintf(stderr, "Unknown process type '%s' specified.",
......
...@@ -9,19 +9,6 @@ ...@@ -9,19 +9,6 @@
namespace remoting { namespace remoting {
// "--elevate=<binary>" requests |binary| to be launched elevated (possibly
// causing a UAC prompt).
extern const char kElevateSwitchName[];
// "--type=<type>" specifies the kind of process to run.
extern const char kProcessTypeSwitchName[];
extern const char kProcessTypeController[];
extern const char kProcessTypeDaemon[];
extern const char kProcessTypeDesktop[];
extern const char kProcessTypeHost[];
extern const char kProcessTypeRdpDesktopSession[];
// The common entry point exported from remoting_core.dll. It uses // The common entry point exported from remoting_core.dll. It uses
// "--type==<type>" command line parameter to determine the kind of process it // "--type==<type>" command line parameter to determine the kind of process it
// needs to run. // needs to run.
......
...@@ -17,6 +17,13 @@ const char kProcessTypeDaemon[] = "daemon"; ...@@ -17,6 +17,13 @@ const char kProcessTypeDaemon[] = "daemon";
const char kProcessTypeDesktop[] = "desktop"; const char kProcessTypeDesktop[] = "desktop";
const char kProcessTypeHost[] = "host"; const char kProcessTypeHost[] = "host";
const char kProcessTypeRdpDesktopSession[] = "rdp_desktop_session"; const char kProcessTypeRdpDesktopSession[] = "rdp_desktop_session";
const char kProcessTypeEvaluateCapability[] = "evaluate_capability";
const char kEvaluateCapabilitySwitchName[] = "evaluate-type";
const char kEvaluateTest[] = "test";
const char kEvaluateCrash[] = "crash";
const char kEvaluateForward[] = "forward";
const char kParentWindowSwitchName[] = "parent-window"; const char kParentWindowSwitchName[] = "parent-window";
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
namespace remoting { namespace remoting {
// "--elevate=<binary>" requests |binary| to be launched elevated (possibly
// causing a UAC prompt).
extern const char kElevateSwitchName[]; extern const char kElevateSwitchName[];
// "--help" prints the usage message. // "--help" prints the usage message.
...@@ -28,6 +30,17 @@ extern const char kProcessTypeDaemon[]; ...@@ -28,6 +30,17 @@ extern const char kProcessTypeDaemon[];
extern const char kProcessTypeDesktop[]; extern const char kProcessTypeDesktop[];
extern const char kProcessTypeHost[]; extern const char kProcessTypeHost[];
extern const char kProcessTypeRdpDesktopSession[]; extern const char kProcessTypeRdpDesktopSession[];
extern const char kProcessTypeEvaluateCapability[];
extern const char kEvaluateCapabilitySwitchName[];
// Values for kEvaluateCapabilitySwitchName.
// Executes EvaluateTest() function, this is for test purpose only.
extern const char kEvaluateTest[];
// Executes EvaluateCrash() function, this is for test purpose only.
extern const char kEvaluateCrash[];
// Executes EvaluateForward() function, this is for test purpose only.
extern const char kEvaluateForward[];
// Used to pass the HWND for the parent process to a child process. // Used to pass the HWND for the parent process to a child process.
extern const char kParentWindowSwitchName[]; extern const char kParentWindowSwitchName[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment