xref: /aosp_15_r20/external/perfetto/src/traced/probes/ftrace/atrace_wrapper.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 #include <optional>
28 
29 #include "perfetto/base/build_config.h"
30 #include "perfetto/base/logging.h"
31 #include "perfetto/base/time.h"
32 #include "perfetto/ext/base/android_utils.h"
33 #include "perfetto/ext/base/pipe.h"
34 #include "perfetto/ext/base/string_utils.h"
35 #include "perfetto/ext/base/utils.h"
36 
37 namespace perfetto {
38 
39 namespace {
40 
41 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
42 // Args should include "atrace" for argv[0].
ExecvAtrace(const std::vector<std::string> & args,std::string * atrace_errors)43 bool ExecvAtrace(const std::vector<std::string>& args,
44                  std::string* atrace_errors) {
45   int status = 1;
46 
47   std::vector<char*> argv;
48   // args, and then a null.
49   argv.reserve(1 + args.size());
50   for (const auto& arg : args)
51     argv.push_back(const_cast<char*>(arg.c_str()));
52   argv.push_back(nullptr);
53 
54   // Create the pipe for the child process to return stderr.
55   base::Pipe err_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);
56 
57   pid_t pid = fork();
58   PERFETTO_CHECK(pid >= 0);
59   if (pid == 0) {
60     // Duplicate the write end of the pipe into stderr.
61     if ((dup2(*err_pipe.wr, STDERR_FILENO) == -1)) {
62       const char kError[] = "Unable to duplicate stderr fd";
63       base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
64       _exit(1);
65     }
66 
67     int null_fd = open("/dev/null", O_RDWR);
68     if (null_fd == -1) {
69       const char kError[] = "Unable to open dev null";
70       base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
71       _exit(1);
72     }
73 
74     if ((dup2(null_fd, STDOUT_FILENO) == -1)) {
75       const char kError[] = "Unable to duplicate stdout fd";
76       base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
77       _exit(1);
78     }
79 
80     if ((dup2(null_fd, STDIN_FILENO) == -1)) {
81       const char kError[] = "Unable to duplicate stdin fd";
82       base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
83       _exit(1);
84     }
85 
86     // Close stdin/out + any file descriptor that we might have mistakenly
87     // not marked as FD_CLOEXEC. |err_pipe| is FD_CLOEXEC and will be
88     // automatically closed on exec.
89     for (int i = 0; i < 128; i++) {
90       if (i != STDIN_FILENO && i != STDERR_FILENO && i != STDOUT_FILENO)
91         close(i);
92     }
93 
94     execv("/system/bin/atrace", &argv[0]);
95 
96     // Reached only if execv fails.
97     _exit(1);
98   }
99 
100   // Close the write end of the pipe.
101   err_pipe.wr.reset();
102 
103   // Collect the output from child process.
104   char buffer[4096];
105   std::string error;
106 
107   // Get the read end of the pipe.
108   constexpr uint8_t kFdCount = 1;
109   struct pollfd fds[kFdCount]{};
110   fds[0].fd = *err_pipe.rd;
111   fds[0].events = POLLIN;
112 
113   // Store the start time of atrace and setup the timeout.
114   constexpr auto timeout = base::TimeMillis(20000);
115   auto start = base::GetWallTimeMs();
116   for (;;) {
117     // Check if we are below the timeout and update the select timeout to
118     // the time remaining.
119     auto now = base::GetWallTimeMs();
120     auto remaining = timeout - (now - start);
121     auto timeout_ms = static_cast<int>(remaining.count());
122     if (timeout_ms <= 0) {
123       // Kill atrace.
124       kill(pid, SIGKILL);
125 
126       std::string cmdline = "/system/bin/atrace";
127       for (const auto& arg : args) {
128         cmdline += " " + arg;
129       }
130       error.append("Timed out waiting for atrace (cmdline: " + cmdline + ")");
131       break;
132     }
133 
134     // Wait for the value of the timeout.
135     auto ret = poll(fds, kFdCount, timeout_ms);
136     if (ret == 0 || (ret < 0 && errno == EINTR)) {
137       // Either timeout occurred in poll (in which case continue so that this
138       // will be picked up by our own timeout logic) or we received an EINTR and
139       // we should try again.
140       continue;
141     } else if (ret < 0) {
142       error.append("Error while polling atrace stderr");
143       break;
144     }
145 
146     // Data is available to be read from the fd.
147     int64_t count = PERFETTO_EINTR(read(*err_pipe.rd, buffer, sizeof(buffer)));
148     if (ret < 0 && errno == EAGAIN) {
149       continue;
150     } else if (count < 0) {
151       error.append("Error while reading atrace stderr");
152       break;
153     } else if (count == 0) {
154       // EOF so we can exit this loop.
155       break;
156     }
157     error.append(buffer, static_cast<size_t>(count));
158   }
159 
160   // Wait until the child process exits fully.
161   PERFETTO_EINTR(waitpid(pid, &status, 0));
162 
163   bool ok = WIFEXITED(status) && WEXITSTATUS(status) == 0;
164   if (!ok)
165     PERFETTO_ELOG("%s", error.c_str());
166   if (atrace_errors)
167     atrace_errors->append(error);
168   return ok;
169 }
170 #endif
171 
172 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
173     !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
IsSdkGreaterOrEqualThan(uint32_t val)174 bool IsSdkGreaterOrEqualThan(uint32_t val) {
175   std::string str_value = base::GetAndroidProp("ro.build.version.sdk");
176   if (str_value.empty())
177     return true;
178   auto opt_value = base::CStringToUInt32(str_value.c_str());
179   return !opt_value.has_value() || *opt_value >= val;
180 }
181 #endif
182 
183 }  // namespace
184 
185 AtraceWrapper::~AtraceWrapper() = default;
186 
187 AtraceWrapperImpl::~AtraceWrapperImpl() = default;
188 
RunAtrace(const std::vector<std::string> & args,std::string * atrace_errors)189 bool AtraceWrapperImpl::RunAtrace(const std::vector<std::string>& args,
190                                   std::string* atrace_errors) {
191 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
192   return ExecvAtrace(args, atrace_errors);
193 #else
194   base::ignore_result(args);
195   base::ignore_result(atrace_errors);
196   PERFETTO_LOG("Atrace only supported on Android.");
197   return false;
198 #endif
199 }
200 
SupportsUserspaceOnly()201 bool AtraceWrapperImpl::SupportsUserspaceOnly() {
202 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
203     !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
204   // Sideloaded case. We could be sideloaded on a modern device or an older one.
205   return IsSdkGreaterOrEqualThan(28);  // 28 == Android P.
206 #else
207   // In in-tree builds we know that atrace is current, no runtime checks needed.
208   return true;
209 #endif
210 }
211 
SupportsPreferSdk()212 bool AtraceWrapperImpl::SupportsPreferSdk() {
213 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
214     !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
215   // Sideloaded case. We could be sideloaded on a modern device or an older one.
216   return IsSdkGreaterOrEqualThan(36);  // 35 == Android V.
217 #else
218   // In in-tree builds we know that atrace is current, no runtime checks needed.
219   return true;
220 #endif
221 }
222 
223 }  // namespace perfetto
224