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 #define LOG_TAG "uprobestats"
18 
19 #include <BpfSyscallWrappers.h>
20 #include <android-base/file.h>
21 #include <android-base/logging.h>
22 #include <linux/perf_event.h>
23 
24 #include <string>
25 
26 #include "bpf/BpfMap.h"
27 #include "bpf/BpfRingbuf.h"
28 
29 #include "Bpf.h"
30 
31 namespace android {
32 namespace uprobestats {
33 namespace bpf {
34 
35 const char *PMU_TYPE_FILE = "/sys/bus/event_source/devices/uprobe/type";
36 
bpfPerfEventOpen(const char * filename,int offset,int pid,const char * bpfProgramPath)37 int bpfPerfEventOpen(const char *filename, int offset, int pid,
38                      const char *bpfProgramPath) {
39   android::base::unique_fd bpfProgramFd(
40       android::bpf::retrieveProgram(bpfProgramPath));
41   if (bpfProgramFd < 0) {
42     LOG(ERROR) << "retrieveProgram failed";
43     return -1;
44   }
45 
46   std::string typeStr;
47   if (!android::base::ReadFileToString(PMU_TYPE_FILE, &typeStr)) {
48     LOG(ERROR) << "Failed to open pmu type file";
49     return -1;
50   }
51   int pmu_type = (int)strtol(typeStr.c_str(), NULL, 10);
52 
53   struct perf_event_attr attr = {};
54   attr.sample_period = 1;
55   attr.wakeup_events = 1;
56   attr.config2 = offset;
57   attr.size = sizeof(attr);
58   attr.type = pmu_type;
59   attr.config1 = android::bpf::ptr_to_u64((void *)filename);
60   attr.exclude_kernel = true;
61 
62   int perfEventFd = syscall(__NR_perf_event_open, &attr, pid, /*cpu=*/-1,
63                             /* group_fd=*/-1, PERF_FLAG_FD_CLOEXEC);
64   if (perfEventFd < 0) {
65     LOG(ERROR) << "syscall(__NR_perf_event_open) failed. "
66                << "perfEventFd: " << perfEventFd << " "
67                << "error: " << strerror(errno);
68     return -1;
69   }
70   if (ioctl(perfEventFd, PERF_EVENT_IOC_SET_BPF, int(bpfProgramFd)) < 0) {
71     LOG(ERROR) << "PERF_EVENT_IOC_SET_BPF failed. " << strerror(errno);
72     return -1;
73   }
74   if (ioctl(perfEventFd, PERF_EVENT_IOC_ENABLE, 0) < 0) {
75     LOG(ERROR) << "PERF_EVENT_IOC_ENABLE failed. " << strerror(errno);
76     return -1;
77   }
78   return 0;
79 }
80 
81 template <typename T>
pollRingBuf(const char * mapPath,int timeoutMs)82 std::vector<T> pollRingBuf(const char *mapPath, int timeoutMs) {
83   auto result = android::bpf::BpfRingbuf<T>::Create(mapPath);
84   std::vector<T> vec;
85   if (!result.value()->wait(timeoutMs)) {
86     return vec;
87   }
88   auto callback = [&](const T &value) { vec.push_back(value); };
89   result.value()->ConsumeAll(callback);
90   return vec;
91 }
92 
93 template std::vector<uint64_t> pollRingBuf(const char *mapPath, int timeoutMs);
94 template std::vector<CallResult> pollRingBuf(const char *mapPath,
95                                              int timeoutMs);
96 template std::vector<CallTimestamp> pollRingBuf(const char *mapPath,
97                                                 int timeoutMs);
98 template std::vector<SetUidTempAllowlistStateRecord>
99 pollRingBuf(const char *mapPath, int timeoutMs);
100 
101 template std::vector<UpdateDeviceIdleTempAllowlistRecord>
102 pollRingBuf(const char *mapPath, int timeoutMs);
103 
consumeRingBuf(const char * mapPath)104 std::vector<int32_t> consumeRingBuf(const char *mapPath) {
105   auto result = android::bpf::BpfRingbuf<uint64_t>::Create(mapPath);
106   std::vector<int32_t> vec;
107   auto callback = [&](const uint64_t &value) { vec.push_back(value); };
108   result.value()->ConsumeAll(callback);
109   return vec;
110 }
111 
printRingBuf(const char * mapPath)112 void printRingBuf(const char *mapPath) {
113   auto result = android::bpf::BpfRingbuf<uint64_t>::Create(mapPath);
114   auto callback = [&](const uint64_t &value) {
115     LOG(INFO) << "ringbuf result callback. value: " << value
116               << " mapPath: " << mapPath;
117   };
118   int numConsumed = result.value()->ConsumeAll(callback).value_or(-1);
119   LOG(INFO) << "ring buffer size: " << numConsumed << " mapPath: " << mapPath;
120 }
121 
122 } // namespace bpf
123 } // namespace uprobestats
124 } // namespace android
125