1 /*
2  * Copyright (c) 2024, 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 "LooperWrapper.h"
20 
21 #include <android-base/chrono_utils.h>
22 #include <android-base/result.h>
23 #include <psi/psi.h>
24 #include <utils/Mutex.h>
25 #include <utils/RefBase.h>
26 #include <utils/StrongPointer.h>
27 
28 #include <unistd.h>
29 
30 #include <thread>  // NOLINT(build/c++11)
31 #include <unordered_set>
32 
33 namespace android {
34 namespace automotive {
35 namespace watchdog {
36 
37 constexpr const char kDefaultProcPressureDirPath[] = "/proc/pressure";
38 constexpr const char kMemoryFile[] = "memory";
39 
40 // PSI monitor window over which the PSI thresholds are defined.
41 constexpr std::chrono::microseconds kPsiWindowSizeUs = 1s;
42 
43 // PSI stall levels for different PSI levels.
44 constexpr psi_stall_type kLowPsiStallLevel = PSI_SOME;
45 constexpr psi_stall_type kMediumPsiStallLevel = PSI_FULL;
46 constexpr psi_stall_type kHighPsiStallLevel = PSI_FULL;
47 
48 // Threshold durations for different PSI levels for the above window size.
49 constexpr std::chrono::microseconds kLowThresholdUs = 15ms;
50 constexpr std::chrono::microseconds kMediumThresholdUs = 30ms;
51 constexpr std::chrono::microseconds kHighThresholdUs = 50ms;
52 
53 // Time between consecutive polling of pressure events.
54 constexpr std::chrono::milliseconds kPollingIntervalMillis = 1s;
55 
56 class PressureMonitorInterface : virtual public android::RefBase {
57 public:
58     enum PressureLevel {
59         PRESSURE_LEVEL_NONE = 0,
60         PRESSURE_LEVEL_LOW,
61         PRESSURE_LEVEL_MEDIUM,
62         PRESSURE_LEVEL_HIGH,
63         PRESSURE_LEVEL_COUNT,
64     };
65 
66     // Clients implement and register this callback to get notified on pressure changes.
67     class PressureChangeCallbackInterface : virtual public android::RefBase {
68     public:
~PressureChangeCallbackInterface()69         virtual ~PressureChangeCallbackInterface() {}
70 
71         // Called when the memory pressure level is changed.
72         virtual void onPressureChanged(PressureLevel pressureLevel) = 0;
73     };
74 
75     // Initializes the PSI monitors for pressure levels defined in PressureLevel enum.
76     virtual android::base::Result<void> init() = 0;
77 
78     // Terminates the active PSI monitors and joins the pressure monitor thread.
79     virtual void terminate() = 0;
80 
81     // Returns true when the pressure monitor is enabled.
82     virtual bool isEnabled() = 0;
83 
84     // Starts the pressure monitor thread, which listens for PSI events and notifies clients on
85     // pressure changes.
86     virtual android::base::Result<void> start() = 0;
87 
88     // Registers a callback for pressure change notifications.
89     virtual android::base::Result<void> registerPressureChangeCallback(
90             android::sp<PressureChangeCallbackInterface> callback) = 0;
91 
92     // Unregisters a previously registered pressure change callback.
93     virtual void unregisterPressureChangeCallback(
94             android::sp<PressureChangeCallbackInterface> callback) = 0;
95 
96     // Returns the string value for the given pressure level.
97     static std::string PressureLevelToString(PressureLevel pressureLevel);
98 };
99 
100 // Monitors memory pressure and notifies registered callbacks when the pressure level changes.
101 class PressureMonitor final :
102       public PressureMonitorInterface,
103       virtual public android::MessageHandler {
104 public:
PressureMonitor()105     PressureMonitor() :
106           PressureMonitor(kDefaultProcPressureDirPath, kPollingIntervalMillis, &init_psi_monitor,
107                           &register_psi_monitor, &unregister_psi_monitor, &destroy_psi_monitor,
108                           &epoll_wait) {}
109 
110     // Used by unittest to configure the internal state and mock the outgoing API calls.
PressureMonitor(const std::string & procPressureDirPath,std::chrono::milliseconds pollingIntervalMillis,const std::function<int (enum psi_stall_type,int,int,enum psi_resource)> & initPsiMonitorFunc,const std::function<int (int,int,void *)> & registerPsiMonitorFunc,const std::function<int (int,int)> & unregisterPsiMonitorFunc,const std::function<void (int)> & destroyPsiMonitorFunc,const std::function<int (int,epoll_event *,int,int)> & epollWaitFunc)111     PressureMonitor(const std::string& procPressureDirPath,
112 
113                     std::chrono::milliseconds pollingIntervalMillis,
114                     const std::function<int(enum psi_stall_type, int, int, enum psi_resource)>&
115                             initPsiMonitorFunc,
116                     const std::function<int(int, int, void*)>& registerPsiMonitorFunc,
117                     const std::function<int(int, int)>& unregisterPsiMonitorFunc,
118                     const std::function<void(int)>& destroyPsiMonitorFunc,
119                     const std::function<int(int, epoll_event*, int, int)>& epollWaitFunc) :
120           kProcPressureDirPath(procPressureDirPath),
121           mPollingIntervalMillis(pollingIntervalMillis),
122           mInitPsiMonitorFunc(initPsiMonitorFunc),
123           mRegisterPsiMonitorFunc(registerPsiMonitorFunc),
124           mUnregisterPsiMonitorFunc(unregisterPsiMonitorFunc),
125           mDestroyPsiMonitorFunc(destroyPsiMonitorFunc),
126           mEpollWaitFunc(epollWaitFunc),
127           mHandlerLooper(android::sp<LooperWrapper>::make()),
128           mIsEnabled(false),
129           mIsMonitorActive(false),
130           mPsiEpollFd(-1),
131           mLastPollElapsedRealTimeNs(0),
132           mLatestPressureLevel(PRESSURE_LEVEL_NONE) {}
133 
134     // Overrides PressureMonitorInterface methods.
135     android::base::Result<void> init() override;
136 
137     void terminate() override;
138 
isEnabled()139     bool isEnabled() override {
140         Mutex::Autolock lock(mMutex);
141         return mIsEnabled;
142     }
143 
144     android::base::Result<void> start() override;
145 
146     android::base::Result<void> registerPressureChangeCallback(
147             android::sp<PressureChangeCallbackInterface> callback) override;
148 
149     void unregisterPressureChangeCallback(
150             android::sp<PressureChangeCallbackInterface> callback) override;
151 
152     // Returns true when the pressure monitor thread is active.
isMonitorActive()153     bool isMonitorActive() { return mIsMonitorActive; }
154 
155 private:
156     template <typename T>
157     struct SpHash {
operatorSpHash158         size_t operator()(const sp<T>& k) const { return std::hash<T*>()(k.get()); }
159     };
160     // Looper messages to post / handle pressure monitor events.
161     enum LooperMessage {
162         MONITOR_PRESSURE = 0,
163         NOTIFY_PRESSURE_CHANGE,
164         LOOPER_MESSAGE_COUNT,
165     };
166     // Contains information about a pressure level.
167     struct PressureLevelInfo {
168         const PressureLevel kPressureLevel = PRESSURE_LEVEL_NONE;
169         const psi_stall_type kStallType = PSI_TYPE_COUNT;
170         const std::chrono::microseconds kThresholdUs = 0us;
171         int psiMonitorFd = -1;
172     };
173 
174     // Initializes the PSI monitors for different pressure levels.
175     android::base::Result<void> initializePsiMonitorsLocked();
176 
177     // Destroys active PSI monitors.
178     void destroyActivePsiMonitorsLocked();
179 
180     // Monitors current pressure levels.
181     android::base::Result<void> monitorPressure();
182 
183     // Waits for the latest PSI events and returns the latest pressure level.
184     android::base::Result<PressureLevel> waitForLatestPressureLevel(int psiEpollFd,
185                                                                     epoll_event* events,
186                                                                     size_t maxEvents);
187 
188     // Handles the looper messages.
189     void handleMessage(const Message& message);
190 
191     // Notifies the clients of the latest pressure level changes.
192     void notifyPressureChange();
193 
194     // Proc pressure directory path.
195     const std::string kProcPressureDirPath;
196 
197     // Thread that waits for PSI triggers and notifies the pressure changes.
198     std::thread mMonitorThread;
199 
200     // Time between consecutive polling of pressure events. Also used for the epoll_wait timeout.
201     std::chrono::milliseconds mPollingIntervalMillis;
202 
203     // Updated by test to mock the PSI interfaces.
204     std::function<int(enum psi_stall_type, int, int, enum psi_resource)> mInitPsiMonitorFunc;
205     std::function<int(int, int, void*)> mRegisterPsiMonitorFunc;
206     std::function<int(int, int)> mUnregisterPsiMonitorFunc;
207     std::function<void(int)> mDestroyPsiMonitorFunc;
208     std::function<int(int, epoll_event*, int, int)> mEpollWaitFunc;
209 
210     // Lock to guard internal state against multi-threaded access.
211     mutable Mutex mMutex;
212 
213     // Handler looper to monitor pressure and notify callbacks.
214     android::sp<LooperWrapper> mHandlerLooper GUARDED_BY(mMutex);
215 
216     // Set to true only when the required Kernel interfaces are accessible.
217     bool mIsEnabled GUARDED_BY(mMutex);
218 
219     // Indicates whether or not the pressure monitor should continue monitoring.
220     bool mIsMonitorActive GUARDED_BY(mMutex);
221 
222     // Epoll fd used to monitor the psi triggers.
223     int mPsiEpollFd GUARDED_BY(mMutex);
224 
225     // Elapsed real time NS when the last poll was performed.
226     // Used to calculate the next poll uptime.
227     nsecs_t mLastPollElapsedRealTimeNs GUARDED_BY(mMutex);
228 
229     // Latest highest active pressure level since the previous polling.
230     PressureLevel mLatestPressureLevel GUARDED_BY(mMutex);
231 
232     // Cache of supported pressure level info.
233     std::vector<PressureLevelInfo> mPressureLevels GUARDED_BY(mMutex);
234 
235     // Callbacks to notify when the pressure level changes.
236     std::unordered_set<android::sp<PressureChangeCallbackInterface>,
237                        SpHash<PressureChangeCallbackInterface>>
238             mPressureChangeCallbacks GUARDED_BY(mMutex);
239 };
240 
241 }  // namespace watchdog
242 }  // namespace automotive
243 }  // namespace android
244