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 ®ister_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