1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/ext/base/file_utils.h"
18 #include "perfetto/ext/base/getopt.h"
19 #include "perfetto/ext/base/string_utils.h"
20 #include "perfetto/ext/base/unix_task_runner.h"
21 #include "perfetto/ext/base/version.h"
22 #include "perfetto/ext/base/watchdog.h"
23 #include "perfetto/ext/traced/traced.h"
24 #include "perfetto/tracing/default_socket.h"
25 #include "src/traced_relay/relay_service.h"
26
27 namespace perfetto {
28 namespace {
PrintUsage(const char * prog_name)29 void PrintUsage(const char* prog_name) {
30 fprintf(stderr, R"(
31 Relays trace data to a remote tracing service. Cannot run alongside the "traced"
32 daemon.
33
34 Usage: %s [OPTION]...
35
36 Options:
37 --background
38 Run as a background process.
39 --set-socket-permissions <GROUP>:<MODE>
40 Set group ownership and permissions for the listening socket.
41 Example: traced-producer:0660 (rw-rw----)
42 --version
43 Display version information and exit.
44
45 Environment Variable:
46 PERFETTO_RELAY_SOCK_NAME
47 Socket name of the remote tracing service.
48 Example: 192.168.0.1:20001 or vsock://2:20001
49
50 Example:
51 PERFETTO_RELAY_SOCK_NAME=192.168.0.1:20001 %s \
52 --set-socket-permissions traced-producer:0660
53
54 Starts the service, relaying trace data to 192.168.0.1:20001.
55 The local listening socket's group is set to "traced-producer" with
56 permissions 0660.
57 )",
58 prog_name, prog_name);
59 }
60
61 } // namespace
62
RelayServiceMain(int argc,char ** argv)63 static int RelayServiceMain(int argc, char** argv) {
64 enum LongOption {
65 OPT_VERSION = 1000,
66 OPT_SET_SOCKET_PERMISSIONS = 1001,
67 OPT_BACKGROUND,
68 };
69
70 bool background = false;
71
72 static const option long_options[] = {
73 {"background", no_argument, nullptr, OPT_BACKGROUND},
74 {"version", no_argument, nullptr, OPT_VERSION},
75 {"set-socket-permissions", required_argument, nullptr,
76 OPT_SET_SOCKET_PERMISSIONS},
77 {nullptr, 0, nullptr, 0}};
78
79 std::string listen_socket_group, listen_socket_mode_bits;
80
81 for (;;) {
82 int option = getopt_long(argc, argv, "", long_options, nullptr);
83 if (option == -1)
84 break;
85 switch (option) {
86 case OPT_BACKGROUND:
87 background = true;
88 break;
89 case OPT_VERSION:
90 printf("%s\n", base::GetVersionString());
91 return 0;
92 case OPT_SET_SOCKET_PERMISSIONS: {
93 // Check that the socket permission argument is well formed.
94 auto parts = perfetto::base::SplitString(std::string(optarg), ":");
95 PERFETTO_CHECK(parts.size() == 2);
96 PERFETTO_CHECK(
97 std::all_of(parts.cbegin(), parts.cend(),
98 [](const std::string& part) { return !part.empty(); }));
99 listen_socket_group = parts[0];
100 listen_socket_mode_bits = parts[1];
101 break;
102 }
103 default:
104 PrintUsage(argv[0]);
105 return 1;
106 }
107 }
108
109 if (!GetRelaySocket()) {
110 PrintUsage(argv[0]);
111 return 1;
112 }
113
114 if (background) {
115 base::Daemonize([] { return 0; });
116 }
117
118 base::UnixTaskRunner task_runner;
119 auto svc = std::make_unique<RelayService>(&task_runner);
120
121 // traced_relay binds to the producer socket of the `traced` service. When
122 // built for Android, this socket is created and bound during init, and its
123 // file descriptor is passed through the environment variable.
124 const char* env_prod = getenv("ANDROID_SOCKET_traced_producer");
125 base::ScopedFile producer_fd;
126 if (env_prod) {
127 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
128 PERFETTO_CHECK(false);
129 #else
130 auto opt_fd = base::CStringToInt32(env_prod);
131 if (opt_fd.has_value())
132 producer_fd.reset(*opt_fd);
133
134 svc->Start(std::move(producer_fd), GetRelaySocket());
135 #endif
136 } else {
137 auto listen_socket = GetProducerSocket();
138 remove(listen_socket);
139 if (!listen_socket_group.empty()) {
140 auto status = base::SetFilePermissions(listen_socket, listen_socket_group,
141 listen_socket_mode_bits);
142 if (!status.ok()) {
143 PERFETTO_ELOG("Failed to set socket permissions: %s",
144 status.c_message());
145 return 1;
146 }
147 }
148
149 svc->Start(listen_socket, GetRelaySocket());
150 }
151
152 // Set the CPU limit and start the watchdog running. The memory limit will
153 // be set inside the service code as it relies on the size of buffers.
154 // The CPU limit is the generic one defined in watchdog.h.
155 base::Watchdog* watchdog = base::Watchdog::GetInstance();
156 watchdog->SetCpuLimit(base::kWatchdogDefaultCpuLimit,
157 base::kWatchdogDefaultCpuWindow);
158 watchdog->Start();
159
160 PERFETTO_ILOG("Started traced_relay, listening on %s, forwarding to %s",
161 GetProducerSocket(), GetRelaySocket());
162
163 task_runner.Run();
164 return 0;
165 }
166 } // namespace perfetto
167
main(int argc,char ** argv)168 int main(int argc, char** argv) {
169 return perfetto::RelayServiceMain(argc, argv);
170 }
171