1 /* 2 * Copyright (C) 2018 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 <chrono> 20 #include <vector> 21 22 #include <mediautils/TimerThread.h> 23 24 namespace android::mediautils { 25 26 // A class monitoring execution time for a code block (scoped variable) and causing an assert 27 // if it exceeds a certain time 28 29 class TimeCheck { 30 public: 31 32 // Duration for TimeCheck is based on steady_clock, typically nanoseconds. 33 using Duration = std::chrono::steady_clock::duration; 34 35 // Duration for printing is in milliseconds, using float for additional precision. 36 using FloatMs = std::chrono::duration<float, std::milli>; 37 38 // OnTimerFunc is the callback function with 2 parameters. 39 // bool timeout (which is true when the TimeCheck object 40 // times out, false when the TimeCheck object is 41 // destroyed or leaves scope before the timer expires.) 42 // float elapsedMs (the elapsed time to this event). 43 using OnTimerFunc = std::function<void(bool /* timeout */, float /* elapsedMs */ )>; 44 45 /** 46 * Returns the default timeout to use for TimeCheck. 47 * 48 * The default timeout of 3000ms (kDefaultTimeoutDurationMs) is chosen to be less than 49 * the system server watchdog timeout, and can be changed by the sysprop 50 * audio.timecheck.timeout_duration_ms. 51 * A second chance wait may be set to extend the check. 52 */ 53 static TimeCheck::Duration getDefaultTimeoutDuration(); 54 55 /** 56 * Returns the second chance timeout to use for TimeCheck. 57 * 58 * Due to suspend abort not incrementing the monotonic clock, 59 * we allow another second chance timeout after the first timeout expires. 60 * The second chance timeout default of 2000ms (kDefaultSecondChanceDurationMs) 61 * may be changed by the sysprop audio.timecheck.second_chance_duration_ms. 62 * 63 * The total timeout is therefore 64 * getDefaultTimeoutDuration() + getDefaultSecondChanceDuration(), 65 * and the result is more stable when the monotonic clock increments during suspend. 66 */ 67 static TimeCheck::Duration getDefaultSecondChanceDuration(); 68 69 /** 70 * TimeCheck is a RAII object which will notify a callback 71 * on timer expiration or when the object is deallocated. 72 * 73 * TimeCheck is used as a watchdog and aborts by default on timer expiration. 74 * When it aborts, it will also send a debugger signal to pids passed in through 75 * setAudioHalPids(). 76 * 77 * If the callback function returns for timeout it will not be called again for 78 * the deallocation. 79 * 80 * \param tag string associated with the TimeCheck object. 81 * \param onTimer callback function with 2 parameters (described above in OnTimerFunc). 82 * The callback when timeout is true will be called on a different thread. 83 * This will cancel the callback on the destructor but is not guaranteed 84 * to block for callback completion if it is already in progress 85 * (for maximum concurrency and reduced deadlock potential), so use proper 86 * lifetime analysis (e.g. shared or weak pointers). 87 * \param requestedTimeoutDuration timeout in milliseconds. 88 * A zero timeout means no timeout is set - 89 * the callback is called only when 90 * the TimeCheck object is destroyed or leaves scope. 91 * \param secondChanceDuration additional milliseconds to wait if the first timeout expires. 92 * This is used to prevent false timeouts if the steady (monotonic) 93 * clock advances on aborted suspend. 94 * \param crashOnTimeout true if the object issues an abort on timeout. 95 */ 96 explicit TimeCheck(std::string_view tag, OnTimerFunc&& onTimer, 97 Duration requestedTimeoutDuration, Duration secondChanceDuration, 98 bool crashOnTimeout); 99 100 TimeCheck() = default; 101 // Remove copy constructors as there should only be one call to the destructor. 102 // Move is kept implicitly disabled, but would be logically consistent if enabled. 103 TimeCheck(const TimeCheck& other) = delete; 104 TimeCheck& operator=(const TimeCheck&) = delete; 105 106 ~TimeCheck(); 107 static std::string toString(); 108 static void setAudioHalPids(const std::vector<pid_t>& pids); 109 static std::vector<pid_t> getAudioHalPids(); 110 static std::string signalAudioHals(); 111 112 private: 113 // Helper class for handling events. 114 // The usage here is const safe. 115 class TimeCheckHandler { 116 public: 117 template <typename S, typename F> TimeCheckHandler(S && _tag,F && _onTimer,bool _crashOnTimeout,Duration _timeoutDuration,Duration _secondChanceDuration,std::chrono::system_clock::time_point _startSystemTime,pid_t _tid)118 TimeCheckHandler(S&& _tag, F&& _onTimer, bool _crashOnTimeout, 119 Duration _timeoutDuration, Duration _secondChanceDuration, 120 std::chrono::system_clock::time_point _startSystemTime, 121 pid_t _tid) 122 : tag(std::forward<S>(_tag)) 123 , onTimer(std::forward<F>(_onTimer)) 124 , crashOnTimeout(_crashOnTimeout) 125 , timeoutDuration(_timeoutDuration) 126 , secondChanceDuration(_secondChanceDuration) 127 , startSystemTime(_startSystemTime) 128 , tid(_tid) 129 {} 130 const FixedString62 tag; 131 const OnTimerFunc onTimer; 132 const bool crashOnTimeout; 133 const Duration timeoutDuration; 134 const Duration secondChanceDuration; 135 const std::chrono::system_clock::time_point startSystemTime; 136 const pid_t tid; 137 void onCancel(TimerThread::Handle handle) const; 138 void onTimeout(TimerThread::Handle handle) const; 139 }; 140 141 // Returns a string that represents the timeout vs elapsed time, 142 // and diagnostics if there are any potential issues. 143 static std::string analyzeTimeouts( 144 float timeoutMs, float secondChanceMs, 145 float elapsedSteadyMs, float elapsedSystemMs); 146 147 static TimerThread& getTimeCheckThread(); 148 static void accessAudioHalPids(std::vector<pid_t>* pids, bool update); 149 150 // mTimeCheckHandler is immutable, prefer to be first initialized, last destroyed. 151 // Technically speaking, we do not need a shared_ptr here because TimerThread::cancelTask() 152 // is mutually exclusive of the callback, but the price paid for lifetime safety is minimal. 153 const std::shared_ptr<const TimeCheckHandler> mTimeCheckHandler; 154 const TimerThread::Handle mTimerHandle = TimerThread::INVALID_HANDLE; 155 }; 156 157 // Returns a TimeCheck object that sends info to MethodStatistics 158 // obtained from getStatisticsForClass(className). 159 TimeCheck makeTimeCheckStatsForClassMethod( 160 std::string_view className, std::string_view methodName); 161 162 // A handy statement-like macro to put at the beginning of almost every method 163 // which calls into HAL. Note that it requires the class to implement 'getClassName'. 164 #define TIME_CHECK() auto timeCheck = \ 165 mediautils::makeTimeCheckStatsForClassMethod(getClassName(), __func__) 166 167 } // namespace android::mediautils 168