// 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 #include "base/base_paths.h" #include "base/check.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/notreached.h" #include "base/path_service.h" #include "base/process/kill.h" #include "base/process/launch.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "remoting/host/base/host_exit_codes.h" #include "remoting/host/base/switches.h" #include "remoting/host/ipc_constants.h" #if BUILDFLAG(IS_WIN) #include "remoting/host/win/evaluate_3d_display_mode.h" #include "remoting/host/win/evaluate_d3d.h" #endif namespace remoting { // TODO(crbug.com/1144161): Do not perform blocking operations on the IO thread. class ScopedBypassIOThreadRestrictions : public base::ScopedAllowBlocking {}; namespace { // 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 uses capability_test_stub in unittest, or tries to use current // binary if supported, otherwise it falls back to use the default binary. base::FilePath BuildHostBinaryPath() { base::FilePath path; bool result = base::PathService::Get(base::FILE_EXE, &path); DCHECK(result); base::FilePath directory; result = base::PathService::Get(base::DIR_EXE, &directory); DCHECK(result); #if BUILDFLAG(IS_WIN) if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_unittests.exe")) { return directory.Append(FILE_PATH_LITERAL("capability_test_stub.exe")); } #else if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_unittests")) { return directory.Append(FILE_PATH_LITERAL("capability_test_stub")); } #endif #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 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; } return directory.Append(FILE_PATH_LITERAL("remoting_me2me_host")); #elif BUILDFLAG(IS_APPLE) if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_me2me_host")) { return path; } return directory.Append(FILE_PATH_LITERAL( "remoting_me2me_host.app/Contents/MacOS/remoting_me2me_host")); #elif BUILDFLAG(IS_WIN) 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; } return directory.Append(FILE_PATH_LITERAL("remoting_host.exe")); #else #error "BuildHostBinaryPath is not implemented for current platform." #endif } } // namespace int EvaluateCapabilityLocally(const std::string& type) { #if BUILDFLAG(IS_WIN) if (type == kEvaluateD3D) { return EvaluateD3D(); } if (type == kEvaluate3dDisplayMode) { return Evaluate3dDisplayMode(); } #endif 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; } // TODO(crbug.com/1144161): Do not perform blocking operations on the IO // thread. ScopedBypassIOThreadRestrictions bypass; #if DCHECK_IS_ON() && !BUILDFLAG(IS_WIN) const bool result = #endif base::GetAppOutputWithExitCode(command, output, &exit_code); // On Windows, base::GetAppOutputWithExitCode() usually returns false when // receiving "unknown" exit code. See // https://cs.chromium.org/chromium/src/base/process/launch_win.cc?rcl=39ec40095376e8d977decbdc5d7ca28ba7d39cf2&l=130 #if DCHECK_IS_ON() && !BUILDFLAG(IS_WIN) DCHECK(result) << "Failed to execute process " << command.GetCommandLineString() << ", exit code " << exit_code; #endif return exit_code; } } // namespace remoting