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