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