1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "remoting/host/evaluate_capability.h"
6
7 #include <iostream>
8
9 #include "base/base_paths.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/notreached.h"
14 #include "base/path_service.h"
15 #include "base/process/kill.h"
16 #include "base/process/launch.h"
17 #include "build/build_config.h"
18 #include "remoting/host/host_exit_codes.h"
19 #include "remoting/host/ipc_constants.h"
20 #include "remoting/host/switches.h"
21
22 #if defined(OS_WIN)
23 #include "remoting/host/win/evaluate_3d_display_mode.h"
24 #include "remoting/host/win/evaluate_d3d.h"
25 #endif
26
27 namespace remoting {
28
29 namespace {
30
31 // Returns the full path of the binary file we should use to evaluate the
32 // capability. According to the platform and executing environment, return of
33 // this function may vary. But in one process, the return value is guaranteed to
34 // be the same.
35 // This function uses capability_test_stub in unittest, or tries to use current
36 // binary if supported, otherwise it falls back to use the default binary.
BuildHostBinaryPath()37 base::FilePath BuildHostBinaryPath() {
38 base::FilePath path;
39 bool result = base::PathService::Get(base::FILE_EXE, &path);
40 DCHECK(result);
41 base::FilePath directory;
42 result = base::PathService::Get(base::DIR_EXE, &directory);
43 DCHECK(result);
44 #if defined(OS_WIN)
45 if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_unittests.exe")) {
46 return directory.Append(FILE_PATH_LITERAL("capability_test_stub.exe"));
47 }
48 #else
49 if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_unittests")) {
50 return directory.Append(FILE_PATH_LITERAL("capability_test_stub"));
51 }
52 #endif
53
54 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
55 if (path.BaseName().value() ==
56 FILE_PATH_LITERAL("chrome-remote-desktop-host")) {
57 return path;
58 }
59 if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_me2me_host")) {
60 return path;
61 }
62
63 return directory.Append(FILE_PATH_LITERAL("remoting_me2me_host"));
64 #elif defined(OS_APPLE)
65 if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_me2me_host")) {
66 return path;
67 }
68
69 return directory.Append(FILE_PATH_LITERAL(
70 "remoting_me2me_host.app/Contents/MacOS/remoting_me2me_host"));
71 #elif defined(OS_WIN)
72 if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_console.exe")) {
73 return path;
74 }
75 if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_desktop.exe")) {
76 return path;
77 }
78 if (path.BaseName().value() == FILE_PATH_LITERAL("remoting_host.exe")) {
79 return path;
80 }
81
82 return directory.Append(FILE_PATH_LITERAL("remoting_host.exe"));
83 #else
84 #error "BuildHostBinaryPath is not implemented for current platform."
85 #endif
86 }
87
88 } // namespace
89
EvaluateCapabilityLocally(const std::string & type)90 int EvaluateCapabilityLocally(const std::string& type) {
91 #if defined(OS_WIN)
92 if (type == kEvaluateD3D) {
93 return EvaluateD3D();
94 }
95 if (type == kEvaluate3dDisplayMode) {
96 return Evaluate3dDisplayMode();
97 }
98 #endif
99
100 return kInvalidCommandLineExitCode;
101 }
102
EvaluateCapability(const std::string & type,std::string * output)103 int EvaluateCapability(const std::string& type,
104 std::string* output /* = nullptr */) {
105 base::CommandLine command(BuildHostBinaryPath());
106 command.AppendSwitchASCII(kProcessTypeSwitchName,
107 kProcessTypeEvaluateCapability);
108 command.AppendSwitchASCII(kEvaluateCapabilitySwitchName, type);
109
110 int exit_code;
111 std::string dummy_output;
112 if (!output) {
113 output = &dummy_output;
114 }
115
116 bool result = base::GetAppOutputWithExitCode(command, output, &exit_code);
117 #if defined(OS_WIN)
118 // On Windows, base::GetAppOutputWithExitCode() usually returns false when
119 // receiving "unknown" exit code. See
120 // https://cs.chromium.org/chromium/src/base/process/launch_win.cc?rcl=39ec40095376e8d977decbdc5d7ca28ba7d39cf2&l=130
121 // But we forward the |exit_code| through return value, so the return value of
122 // base::GetAppOutputWithExitCode() should be ignored.
123 result = true;
124 #endif
125 if (!result) {
126 LOG(ERROR) << "Failed to execute process "
127 << command.GetCommandLineString()
128 << ", exit code "
129 << exit_code;
130 // This should not happen.
131 NOTREACHED();
132 }
133
134 return exit_code;
135 }
136
137 } // namespace remoting
138