xref: /aosp_15_r20/external/perfetto/src/profiling/perf/proc_descriptors.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2020 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/profiling/perf/proc_descriptors.h"
18 
19 #include <fcntl.h>
20 #include <signal.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 
24 #include "perfetto/ext/base/string_utils.h"
25 
26 namespace perfetto {
27 
~ProcDescriptorDelegate()28 ProcDescriptorDelegate::~ProcDescriptorDelegate() {}
29 
~ProcDescriptorGetter()30 ProcDescriptorGetter::~ProcDescriptorGetter() {}
31 
32 // DirectDescriptorGetter:
33 
~DirectDescriptorGetter()34 DirectDescriptorGetter::~DirectDescriptorGetter() {}
35 
SetDelegate(ProcDescriptorDelegate * delegate)36 void DirectDescriptorGetter::SetDelegate(ProcDescriptorDelegate* delegate) {
37   delegate_ = delegate;
38 }
39 
GetDescriptorsForPid(pid_t pid)40 void DirectDescriptorGetter::GetDescriptorsForPid(pid_t pid) {
41   base::StackString<128> dir_buf("/proc/%d", pid);
42   auto dir_fd = base::ScopedFile(
43       open(dir_buf.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
44   if (!dir_fd) {
45     if (errno != ENOENT)  // not surprising if the process has quit
46       PERFETTO_PLOG("Failed to open [%s]", dir_buf.c_str());
47 
48     return;
49   }
50 
51   struct stat stat_buf;
52   if (fstat(dir_fd.get(), &stat_buf) == -1) {
53     PERFETTO_PLOG("Failed to stat [%s]", dir_buf.c_str());
54     return;
55   }
56 
57   auto maps_fd =
58       base::ScopedFile{openat(dir_fd.get(), "maps", O_RDONLY | O_CLOEXEC)};
59   if (!maps_fd) {
60     if (errno != ENOENT)  // not surprising if the process has quit
61       PERFETTO_PLOG("Failed to open %s/maps", dir_buf.c_str());
62 
63     return;
64   }
65 
66   auto mem_fd =
67       base::ScopedFile{openat(dir_fd.get(), "mem", O_RDONLY | O_CLOEXEC)};
68   if (!mem_fd) {
69     if (errno != ENOENT)  // not surprising if the process has quit
70       PERFETTO_PLOG("Failed to open %s/mem", dir_buf.c_str());
71 
72     return;
73   }
74 
75   delegate_->OnProcDescriptors(pid, stat_buf.st_uid, std::move(maps_fd),
76                                std::move(mem_fd));
77 }
78 
79 // AndroidRemoteDescriptorGetter:
80 
81 AndroidRemoteDescriptorGetter::~AndroidRemoteDescriptorGetter() = default;
82 
SetDelegate(ProcDescriptorDelegate * delegate)83 void AndroidRemoteDescriptorGetter::SetDelegate(
84     ProcDescriptorDelegate* delegate) {
85   delegate_ = delegate;
86 }
87 
88 #if !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
GetDescriptorsForPid(pid_t)89 void AndroidRemoteDescriptorGetter::GetDescriptorsForPid(pid_t) {
90   PERFETTO_FATAL("Unexpected build type for AndroidRemoteDescriptorGetter");
91 }
92 #else
GetDescriptorsForPid(pid_t pid)93 void AndroidRemoteDescriptorGetter::GetDescriptorsForPid(pid_t pid) {
94   constexpr static int kPerfProfilerSignalValue = 1;
95   constexpr static int kProfilerSignal = __SIGRTMIN + 4;
96 
97   PERFETTO_DLOG("Sending signal to pid [%d]", pid);
98   union sigval signal_value;
99   signal_value.sival_int = kPerfProfilerSignalValue;
100   if (sigqueue(pid, kProfilerSignal, signal_value) != 0 && errno != ESRCH) {
101     PERFETTO_DPLOG("Failed sigqueue(%d)", pid);
102   }
103 }
104 #endif
105 
OnNewIncomingConnection(base::UnixSocket *,std::unique_ptr<base::UnixSocket> new_connection)106 void AndroidRemoteDescriptorGetter::OnNewIncomingConnection(
107     base::UnixSocket*,
108     std::unique_ptr<base::UnixSocket> new_connection) {
109   PERFETTO_DLOG("remote fds: new connection from pid [%d]",
110                 static_cast<int>(new_connection->peer_pid_linux()));
111 
112   active_connections_.emplace(new_connection.get(), std::move(new_connection));
113 }
114 
OnDisconnect(base::UnixSocket * self)115 void AndroidRemoteDescriptorGetter::OnDisconnect(base::UnixSocket* self) {
116   PERFETTO_DLOG("remote fds: disconnect from pid [%d]",
117                 static_cast<int>(self->peer_pid_linux()));
118 
119   auto it = active_connections_.find(self);
120   PERFETTO_CHECK(it != active_connections_.end());
121   active_connections_.erase(it);
122 }
123 
124 // Note: this callback will fire twice for a given connection. Once for the file
125 // descriptors, and once during the disconnect (with 0 bytes available in the
126 // socket).
OnDataAvailable(base::UnixSocket * self)127 void AndroidRemoteDescriptorGetter::OnDataAvailable(base::UnixSocket* self) {
128   // Expect two file descriptors (maps, followed by mem).
129   base::ScopedFile fds[2];
130   char buf[1];
131   size_t received_bytes =
132       self->Receive(buf, sizeof(buf), fds, base::ArraySize(fds));
133 
134   PERFETTO_DLOG("remote fds: received %zu bytes", received_bytes);
135   if (!received_bytes)
136     return;
137 
138   delegate_->OnProcDescriptors(self->peer_pid_linux(), self->peer_uid_posix(),
139                                std::move(fds[0]), std::move(fds[1]));
140 }
141 
142 }  // namespace perfetto
143