blob: c11286366c4901b9e7be49cb5dcda7f7595ab92e [file] [log] [blame]
Eric Laurent3528c932018-02-23 17:17:22 -08001/*
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-Tsvi1ea62c92021-11-10 14:38:27 -080017#pragma once
Eric Laurent3528c932018-02-23 17:17:22 -080018
Andy Hungf8ab0932022-06-13 19:49:43 -070019#include <chrono>
Eric Laurent42896a02019-09-27 15:40:33 -070020#include <vector>
Eric Laurent3528c932018-02-23 17:17:22 -080021
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080022#include <mediautils/TimerThread.h>
23
Andy Hung5c6d68a2022-03-09 21:54:59 -080024namespace android::mediautils {
Eric Laurent3528c932018-02-23 17:17:22 -080025
26// A class monitoring execution time for a code block (scoped variable) and causing an assert
27// if it exceeds a certain time
28
29class TimeCheck {
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080030 public:
Andy Hung2aa15102022-06-13 19:49:43 -070031
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).
Andy Hung5c6d68a2022-03-09 21:54:59 -080043 using OnTimerFunc = std::function<void(bool /* timeout */, float /* elapsedMs */ )>;
44
Andy Hungcb899102024-08-06 15:17:16 -070045 /**
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();
Andy Hungf8ab0932022-06-13 19:49:43 -070054
Andy Hungcb899102024-08-06 15:17:16 -070055 /**
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();
Eric Laurent3528c932018-02-23 17:17:22 -080068
Andy Hung5c6d68a2022-03-09 21:54:59 -080069 /**
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.
Andy Hung2aa15102022-06-13 19:49:43 -070081 * \param onTimer callback function with 2 parameters (described above in OnTimerFunc).
Andy Hung5c6d68a2022-03-09 21:54:59 -080082 * The callback when timeout is true will be called on a different thread.
Andy Hunga2a1ac32022-03-18 16:12:11 -070083 * 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).
Andy Hungf8ab0932022-06-13 19:49:43 -070087 * \param requestedTimeoutDuration timeout in milliseconds.
Andy Hunga2a1ac32022-03-18 16:12:11 -070088 * A zero timeout means no timeout is set -
89 * the callback is called only when
90 * the TimeCheck object is destroyed or leaves scope.
Andy Hungf8ab0932022-06-13 19:49:43 -070091 * \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.
Andy Hung5c6d68a2022-03-09 21:54:59 -080094 * \param crashOnTimeout true if the object issues an abort on timeout.
95 */
Andy Hungf8ab0932022-06-13 19:49:43 -070096 explicit TimeCheck(std::string_view tag, OnTimerFunc&& onTimer,
97 Duration requestedTimeoutDuration, Duration secondChanceDuration,
98 bool crashOnTimeout);
Andy Hunga2a1ac32022-03-18 16:12:11 -070099
100 TimeCheck() = default;
Andy Hung5c6d68a2022-03-09 21:54:59 -0800101 // 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
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800106 ~TimeCheck();
Andy Hunga2a1ac32022-03-18 16:12:11 -0700107 static std::string toString();
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800108 static void setAudioHalPids(const std::vector<pid_t>& pids);
109 static std::vector<pid_t> getAudioHalPids();
Mikhail Naganov380cf5d2024-09-18 14:08:16 -0700110 static std::string signalAudioHals();
Eric Laurent3528c932018-02-23 17:17:22 -0800111
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800112 private:
Andy Hung5c6d68a2022-03-09 21:54:59 -0800113 // Helper class for handling events.
114 // The usage here is const safe.
115 class TimeCheckHandler {
116 public:
Andy Hung35f96152022-07-15 15:18:59 -0700117 template <typename S, typename F>
118 TimeCheckHandler(S&& _tag, F&& _onTimer, bool _crashOnTimeout,
Andy Hungf8ab0932022-06-13 19:49:43 -0700119 Duration _timeoutDuration, Duration _secondChanceDuration,
Andy Hung2aa15102022-06-13 19:49:43 -0700120 std::chrono::system_clock::time_point _startSystemTime,
Andy Hung35f96152022-07-15 15:18:59 -0700121 pid_t _tid)
122 : tag(std::forward<S>(_tag))
123 , onTimer(std::forward<F>(_onTimer))
124 , crashOnTimeout(_crashOnTimeout)
Andy Hung2aa15102022-06-13 19:49:43 -0700125 , timeoutDuration(_timeoutDuration)
Andy Hungf8ab0932022-06-13 19:49:43 -0700126 , secondChanceDuration(_secondChanceDuration)
Andy Hung2aa15102022-06-13 19:49:43 -0700127 , startSystemTime(_startSystemTime)
Andy Hung35f96152022-07-15 15:18:59 -0700128 , tid(_tid)
129 {}
130 const FixedString62 tag;
Andy Hung5c6d68a2022-03-09 21:54:59 -0800131 const OnTimerFunc onTimer;
132 const bool crashOnTimeout;
Andy Hung2aa15102022-06-13 19:49:43 -0700133 const Duration timeoutDuration;
Andy Hungf8ab0932022-06-13 19:49:43 -0700134 const Duration secondChanceDuration;
Andy Hung2aa15102022-06-13 19:49:43 -0700135 const std::chrono::system_clock::time_point startSystemTime;
Andy Hung5c6d68a2022-03-09 21:54:59 -0800136 const pid_t tid;
Andy Hung5c6d68a2022-03-09 21:54:59 -0800137 void onCancel(TimerThread::Handle handle) const;
Andy Hung2aa15102022-06-13 19:49:43 -0700138 void onTimeout(TimerThread::Handle handle) const;
Andy Hung5c6d68a2022-03-09 21:54:59 -0800139 };
140
Andy Hung2aa15102022-06-13 19:49:43 -0700141 // Returns a string that represents the timeout vs elapsed time,
142 // and diagnostics if there are any potential issues.
143 static std::string analyzeTimeouts(
Andy Hungcb899102024-08-06 15:17:16 -0700144 float timeoutMs, float secondChanceMs,
145 float elapsedSteadyMs, float elapsedSystemMs);
Andy Hung2aa15102022-06-13 19:49:43 -0700146
Andy Hunga2a1ac32022-03-18 16:12:11 -0700147 static TimerThread& getTimeCheckThread();
148 static void accessAudioHalPids(std::vector<pid_t>* pids, bool update);
149
Andy Hung5c6d68a2022-03-09 21:54:59 -0800150 // 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;
Andy Hunga2a1ac32022-03-18 16:12:11 -0700154 const TimerThread::Handle mTimerHandle = TimerThread::INVALID_HANDLE;
Eric Laurent3528c932018-02-23 17:17:22 -0800155};
156
Andy Hung224f82f2022-03-22 00:00:49 -0700157// Returns a TimeCheck object that sends info to MethodStatistics
158// obtained from getStatisticsForClass(className).
159TimeCheck makeTimeCheckStatsForClassMethod(
160 std::string_view className, std::string_view methodName);
161
Mikhail Naganov31d46652023-01-10 18:29:25 +0000162// 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
Andy Hung5c6d68a2022-03-09 21:54:59 -0800167} // namespace android::mediautils