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. |
| 53 | * Currently this is guaranteed to block the destructor |
| 54 | * (potential lock inversion warning here) nevertheless |
| 55 | * it would be safer not to depend on stack contents. |
| 56 | * \param timeoutMs timeout in milliseconds. |
| 57 | * \param crashOnTimeout true if the object issues an abort on timeout. |
| 58 | */ |
| 59 | explicit TimeCheck(std::string tag, OnTimerFunc&& onTimer = {}, |
| 60 | uint32_t timeoutMs = kDefaultTimeOutMs, bool crashOnTimeout = true); |
| 61 | // Remove copy constructors as there should only be one call to the destructor. |
| 62 | // Move is kept implicitly disabled, but would be logically consistent if enabled. |
| 63 | TimeCheck(const TimeCheck& other) = delete; |
| 64 | TimeCheck& operator=(const TimeCheck&) = delete; |
| 65 | |
Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 66 | ~TimeCheck(); |
| 67 | static void setAudioHalPids(const std::vector<pid_t>& pids); |
| 68 | static std::vector<pid_t> getAudioHalPids(); |
Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 69 | |
Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 70 | private: |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 71 | static TimerThread& getTimeCheckThread(); |
Eric Laurent | 42896a0 | 2019-09-27 15:40:33 -0700 | [diff] [blame] | 72 | static void accessAudioHalPids(std::vector<pid_t>* pids, bool update); |
Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 73 | |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 74 | // Helper class for handling events. |
| 75 | // The usage here is const safe. |
| 76 | class TimeCheckHandler { |
| 77 | public: |
| 78 | const std::string tag; |
| 79 | const OnTimerFunc onTimer; |
| 80 | const bool crashOnTimeout; |
| 81 | const std::chrono::system_clock::time_point startTime; |
| 82 | const pid_t tid; |
| 83 | |
| 84 | void onCancel(TimerThread::Handle handle) const; |
| 85 | void onTimeout() const; |
| 86 | }; |
| 87 | |
| 88 | // mTimeCheckHandler is immutable, prefer to be first initialized, last destroyed. |
| 89 | // Technically speaking, we do not need a shared_ptr here because TimerThread::cancelTask() |
| 90 | // is mutually exclusive of the callback, but the price paid for lifetime safety is minimal. |
| 91 | const std::shared_ptr<const TimeCheckHandler> mTimeCheckHandler; |
Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 92 | const TimerThread::Handle mTimerHandle; |
Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 93 | }; |
| 94 | |
Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 95 | } // namespace android::mediautils |