Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 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 | |
Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 17 | #pragma once |
Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 18 | |
Eric Laurent | 42896a0 | 2019-09-27 15:40:33 -0700 | [diff] [blame] | 19 | #include <vector> |
Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 20 | |
Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 21 | #include <mediautils/TimerThread.h> |
| 22 | |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 23 | namespace android::mediautils { |
Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 24 | |
| 25 | // A class monitoring execution time for a code block (scoped variable) and causing an assert |
| 26 | // if it exceeds a certain time |
| 27 | |
| 28 | class TimeCheck { |
Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 29 | public: |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 30 | using OnTimerFunc = std::function<void(bool /* timeout */, float /* elapsedMs */ )>; |
| 31 | |
Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 32 | // The default timeout is chosen to be less than system server watchdog timeout |
| 33 | static constexpr uint32_t kDefaultTimeOutMs = 5000; |
| 34 | |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 35 | /** |
| 36 | * TimeCheck is a RAII object which will notify a callback |
| 37 | * on timer expiration or when the object is deallocated. |
| 38 | * |
| 39 | * TimeCheck is used as a watchdog and aborts by default on timer expiration. |
| 40 | * When it aborts, it will also send a debugger signal to pids passed in through |
| 41 | * setAudioHalPids(). |
| 42 | * |
| 43 | * If the callback function returns for timeout it will not be called again for |
| 44 | * the deallocation. |
| 45 | * |
| 46 | * \param tag string associated with the TimeCheck object. |
| 47 | * \param onTimer callback function with 2 parameters |
| 48 | * bool timeout (which is true when the TimeCheck object |
| 49 | * times out, false when the TimeCheck object is |
| 50 | * destroyed or leaves scope before the timer expires.) |
| 51 | * float elapsedMs (the elapsed time to this event). |
| 52 | * The callback when timeout is true will be called on a different thread. |
Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 53 | * This will cancel the callback on the destructor but is not guaranteed |
| 54 | * to block for callback completion if it is already in progress |
| 55 | * (for maximum concurrency and reduced deadlock potential), so use proper |
| 56 | * lifetime analysis (e.g. shared or weak pointers). |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 57 | * \param timeoutMs timeout in milliseconds. |
Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 58 | * A zero timeout means no timeout is set - |
| 59 | * the callback is called only when |
| 60 | * the TimeCheck object is destroyed or leaves scope. |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 61 | * \param crashOnTimeout true if the object issues an abort on timeout. |
| 62 | */ |
| 63 | explicit TimeCheck(std::string tag, OnTimerFunc&& onTimer = {}, |
| 64 | uint32_t timeoutMs = kDefaultTimeOutMs, bool crashOnTimeout = true); |
Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 65 | |
| 66 | TimeCheck() = default; |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 67 | // Remove copy constructors as there should only be one call to the destructor. |
| 68 | // Move is kept implicitly disabled, but would be logically consistent if enabled. |
| 69 | TimeCheck(const TimeCheck& other) = delete; |
| 70 | TimeCheck& operator=(const TimeCheck&) = delete; |
| 71 | |
Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 72 | ~TimeCheck(); |
Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 73 | static std::string toString(); |
Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 74 | static void setAudioHalPids(const std::vector<pid_t>& pids); |
| 75 | static std::vector<pid_t> getAudioHalPids(); |
Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 76 | |
Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 77 | private: |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 78 | // Helper class for handling events. |
| 79 | // The usage here is const safe. |
| 80 | class TimeCheckHandler { |
| 81 | public: |
| 82 | const std::string tag; |
| 83 | const OnTimerFunc onTimer; |
| 84 | const bool crashOnTimeout; |
| 85 | const std::chrono::system_clock::time_point startTime; |
| 86 | const pid_t tid; |
| 87 | |
| 88 | void onCancel(TimerThread::Handle handle) const; |
| 89 | void onTimeout() const; |
| 90 | }; |
| 91 | |
Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 92 | static TimerThread& getTimeCheckThread(); |
| 93 | static void accessAudioHalPids(std::vector<pid_t>* pids, bool update); |
| 94 | |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 95 | // mTimeCheckHandler is immutable, prefer to be first initialized, last destroyed. |
| 96 | // Technically speaking, we do not need a shared_ptr here because TimerThread::cancelTask() |
| 97 | // is mutually exclusive of the callback, but the price paid for lifetime safety is minimal. |
| 98 | const std::shared_ptr<const TimeCheckHandler> mTimeCheckHandler; |
Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 99 | const TimerThread::Handle mTimerHandle = TimerThread::INVALID_HANDLE; |
Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 100 | }; |
| 101 | |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 102 | } // namespace android::mediautils |