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