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