1 /*
2 * Copyright (C) 2018 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 "src/traced/probes/ftrace/atrace_wrapper.h"
18
19 #include <fcntl.h>
20 #include <poll.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27
28 #include "perfetto/base/logging.h"
29 #include "perfetto/base/pipe.h"
30 #include "perfetto/base/time.h"
31
32 namespace perfetto {
33
34 namespace {
35
36 RunAtraceFunction g_run_atrace_for_testing = nullptr;
37
38 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
39 // Args should include "atrace" for argv[0].
ExecvAtrace(const std::vector<std::string> & args)40 bool ExecvAtrace(const std::vector<std::string>& args) {
41 int status = 1;
42
43 std::vector<char*> argv;
44 // args, and then a null.
45 argv.reserve(1 + args.size());
46 for (const auto& arg : args)
47 argv.push_back(const_cast<char*>(arg.c_str()));
48 argv.push_back(nullptr);
49
50 // Create the pipe for the child process to return stderr.
51 base::Pipe err_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);
52
53 pid_t pid = fork();
54 PERFETTO_CHECK(pid >= 0);
55 if (pid == 0) {
56 // Duplicate the write end of the pipe into stderr.
57 if ((dup2(*err_pipe.wr, STDERR_FILENO) == -1)) {
58 const char kError[] = "Unable to duplicate stderr fd";
59 base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
60 _exit(1);
61 }
62
63 int null_fd = open("/dev/null", O_RDWR);
64 if (null_fd == -1) {
65 const char kError[] = "Unable to open dev null";
66 base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
67 _exit(1);
68 }
69
70 if ((dup2(null_fd, STDOUT_FILENO) == -1)) {
71 const char kError[] = "Unable to duplicate stdout fd";
72 base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
73 _exit(1);
74 }
75
76 if ((dup2(null_fd, STDIN_FILENO) == -1)) {
77 const char kError[] = "Unable to duplicate stdin fd";
78 base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
79 _exit(1);
80 }
81
82 // Close stdin/out + any file descriptor that we might have mistakenly
83 // not marked as FD_CLOEXEC. |err_pipe| is FD_CLOEXEC and will be
84 // automatically closed on exec.
85 for (int i = 0; i < 128; i++) {
86 if (i != STDIN_FILENO && i != STDERR_FILENO && i != STDOUT_FILENO)
87 close(i);
88 }
89
90 execv("/system/bin/atrace", &argv[0]);
91
92 // Reached only if execv fails.
93 _exit(1);
94 }
95
96 // Close the write end of the pipe.
97 err_pipe.wr.reset();
98
99 // Collect the output from child process.
100 char buffer[4096];
101 std::string error;
102
103 // Get the read end of the pipe.
104 constexpr uint8_t kFdCount = 1;
105 struct pollfd fds[kFdCount]{};
106 fds[0].fd = *err_pipe.rd;
107 fds[0].events = POLLIN;
108
109 // Store the start time of atrace and setup the timeout.
110 constexpr auto timeout = base::TimeMillis(7500);
111 auto start = base::GetWallTimeMs();
112 for (;;) {
113 // Check if we are below the timeout and update the select timeout to
114 // the time remaining.
115 auto now = base::GetWallTimeMs();
116 auto remaining = timeout - (now - start);
117 auto timeout_ms = static_cast<int>(remaining.count());
118 if (timeout_ms <= 0) {
119 // Kill atrace.
120 kill(pid, SIGKILL);
121
122 std::string cmdline = "/system/bin/atrace";
123 for (const auto& arg : args) {
124 cmdline += " " + arg;
125 }
126 error.append("Timed out waiting for atrace (cmdline: " + cmdline + ")");
127 break;
128 }
129
130 // Wait for the value of the timeout.
131 auto ret = poll(fds, kFdCount, timeout_ms);
132 if (ret == 0 || (ret < 0 && errno == EINTR)) {
133 // Either timeout occured in poll (in which case continue so that this
134 // will be picked up by our own timeout logic) or we received an EINTR and
135 // we should try again.
136 continue;
137 } else if (ret < 0) {
138 error.append("Error while polling atrace stderr");
139 break;
140 }
141
142 // Data is available to be read from the fd.
143 int64_t count = PERFETTO_EINTR(read(*err_pipe.rd, buffer, sizeof(buffer)));
144 if (ret < 0 && errno == EAGAIN) {
145 continue;
146 } else if (count < 0) {
147 error.append("Error while reading atrace stderr");
148 break;
149 } else if (count == 0) {
150 // EOF so we can exit this loop.
151 break;
152 }
153 error.append(buffer, static_cast<size_t>(count));
154 }
155
156 // Wait until the child process exits fully.
157 PERFETTO_EINTR(waitpid(pid, &status, 0));
158
159 bool ok = WIFEXITED(status) && WEXITSTATUS(status) == 0;
160 if (!ok) {
161 // TODO(lalitm): use the stderr result from atrace.
162 PERFETTO_ELOG("%s", error.c_str());
163 }
164 return ok;
165 }
166 #endif
167
168 } // namespace
169
RunAtrace(const std::vector<std::string> & args)170 bool RunAtrace(const std::vector<std::string>& args) {
171 if (g_run_atrace_for_testing)
172 return g_run_atrace_for_testing(args);
173 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
174 return ExecvAtrace(args);
175 #else
176 PERFETTO_LOG("Atrace only supported on Android.");
177 return false;
178 #endif
179 }
180
SetRunAtraceForTesting(RunAtraceFunction f)181 void SetRunAtraceForTesting(RunAtraceFunction f) {
182 g_run_atrace_for_testing = f;
183 }
184
185 } // namespace perfetto
186