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 #pragma once
18 
19 #include <android-base/thread_annotations.h>
20 
21 #include <memory>
22 #include <vector>
23 
24 #include <stddef.h>
25 
26 #include <memevents/bpf_types.h>
27 
28 namespace android {
29 namespace bpf {
30 namespace memevents {
31 
32 enum MemEventClient {
33     // BASE should always be first, used for lower-bound checks
34     BASE = 0,
35     AMS = BASE,
36     LMKD,
37     /*
38      * Flag to indicate whether this `MemEventListener` instance is used for
39      * testing purposes. This allows us to skip internal calls that would
40      * otherwise interfere with test setup, and mocks for BPF ring buffer,
41      * and BPF program behavior.
42      */
43     TEST_CLIENT,
44     // NR_CLIENTS should always come after the last valid client
45     NR_CLIENTS
46 };
47 
48 class MemBpfRingbuf;
49 
50 class MemEventListener final {
51   public:
52     /*
53      * MemEventListener will `std::abort` when failing to initialize
54      * the bpf ring buffer manager, on a bpf-rb supported kernel.
55      *
56      * If running on a kernel that doesn't support bpf-rb, the listener
57      * will initialize in an invalid state, preventing it from making
58      * any actions/calls.
59      * To check if the listener initialized correctly use `ok()`.
60      */
61     MemEventListener(MemEventClient client, bool attachTpForTests = false);
62     ~MemEventListener();
63 
64     /**
65      * Check if the listener was initialized correctly, with a valid bpf
66      * ring buffer manager on a bpf-rb supported kernel.
67      *
68      * @return true if initialized with a valid bpf rb manager, false
69      * otherwise.
70      */
71     bool ok();
72 
73     /**
74      * Registers the requested memory event to the listener.
75      *
76      * @param event_type Memory event type to listen for.
77      * @return true if registration was successful, false otherwise.
78      */
79     bool registerEvent(mem_event_type_t event_type);
80 
81     /**
82      * Waits for a [registered] memory event notification.
83      *
84      * `listen()` will block until either:
85      *    - Receives a registered memory event
86      *    - Timeout expires
87      *
88      * Note that the default timeout (-1) causes `listen()` to block
89      * indefinitely.
90      *
91      * @param timeout_ms number of milliseconds that listen will block.
92      * @return true if there are new memory events to read, false otherwise.
93      */
94     bool listen(int timeout_ms = -1);
95 
96     /**
97      * Stops listening for a specific memory event type.
98      *
99      * @param event_type Memory event type to stop listening to.
100      * @return true if unregistering was successful, false otherwise
101      */
102     bool deregisterEvent(mem_event_type_t event_type);
103 
104     /**
105      * Closes all the events' file descriptors and `mEpfd`. This will also
106      * gracefully terminate any ongoing `listen()`.
107      */
108     void deregisterAllEvents();
109 
110     /**
111      * Retrieves unread [registered] memory events, and stores them into the
112      * provided `mem_events` vector.
113      *
114      * On first invocation, it will read/store all memory events. After the
115      * initial invocation, it will only read/store new, unread, events.
116      *
117      * @param mem_events vector in which we want to append the read
118      * memory events.
119      * @return true on success, false on failure.
120      */
121     bool getMemEvents(std::vector<mem_event_t>& mem_events);
122 
123     /**
124      * Expose the MemEventClient's ring-buffer file descriptor for polling purposes,
125      * not intended for consumption. To consume use `ConsumeAll()`.
126      *
127      * @return file descriptor (non negative integer), -1 on error.
128      */
129     int getRingBufferFd();
130 
131   private:
132     bool mEventsRegistered[NR_MEM_EVENTS];
133     int mNumEventsRegistered;
134     MemEventClient mClient;
135     /*
136      * BFP ring buffer is designed as single producer single consumer.
137      * Protect against concurrent accesses.
138      */
139     std::mutex mRingBufMutex;
140     std::unique_ptr<MemBpfRingbuf> memBpfRb GUARDED_BY(mRingBufMutex);
141     bool mAttachTpForTests;
142 
143     bool isValidEventType(mem_event_type_t event_type) const;
144 };
145 
146 }  // namespace memevents
147 }  // namespace bpf
148 }  // namespace android
149