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