• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     // The default timeout is chosen to be less than system server watchdog timeout
46     // Note: kDefaultTimeOutMs should be no less than 2 seconds, otherwise spurious timeouts
47     // may occur with system suspend.
48     static constexpr TimeCheck::Duration kDefaultTimeoutDuration = std::chrono::milliseconds(3000);
49 
50     // Due to suspend abort not incrementing the monotonic clock,
51     // we allow another second chance timeout after the first timeout expires.
52     //
53     // The total timeout is therefore kDefaultTimeoutDuration + kDefaultSecondChanceDuration,
54     // and the result is more stable when the monotonic clock increments during suspend.
55     //
56     static constexpr TimeCheck::Duration kDefaultSecondChanceDuration =
57             std::chrono::milliseconds(2000);
58 
59     /**
60      * TimeCheck is a RAII object which will notify a callback
61      * on timer expiration or when the object is deallocated.
62      *
63      * TimeCheck is used as a watchdog and aborts by default on timer expiration.
64      * When it aborts, it will also send a debugger signal to pids passed in through
65      * setAudioHalPids().
66      *
67      * If the callback function returns for timeout it will not be called again for
68      * the deallocation.
69      *
70      * \param tag       string associated with the TimeCheck object.
71      * \param onTimer   callback function with 2 parameters (described above in OnTimerFunc).
72      *                  The callback when timeout is true will be called on a different thread.
73      *                  This will cancel the callback on the destructor but is not guaranteed
74      *                  to block for callback completion if it is already in progress
75      *                  (for maximum concurrency and reduced deadlock potential), so use proper
76      *                  lifetime analysis (e.g. shared or weak pointers).
77      * \param requestedTimeoutDuration timeout in milliseconds.
78      *                  A zero timeout means no timeout is set -
79      *                  the callback is called only when
80      *                  the TimeCheck object is destroyed or leaves scope.
81      * \param secondChanceDuration additional milliseconds to wait if the first timeout expires.
82      *                  This is used to prevent false timeouts if the steady (monotonic)
83      *                  clock advances on aborted suspend.
84      * \param crashOnTimeout true if the object issues an abort on timeout.
85      */
86     explicit TimeCheck(std::string_view tag, OnTimerFunc&& onTimer,
87             Duration requestedTimeoutDuration, Duration secondChanceDuration,
88             bool crashOnTimeout);
89 
90     TimeCheck() = default;
91     // Remove copy constructors as there should only be one call to the destructor.
92     // Move is kept implicitly disabled, but would be logically consistent if enabled.
93     TimeCheck(const TimeCheck& other) = delete;
94     TimeCheck& operator=(const TimeCheck&) = delete;
95 
96     ~TimeCheck();
97     static std::string toString();
98     static void setAudioHalPids(const std::vector<pid_t>& pids);
99     static std::vector<pid_t> getAudioHalPids();
100 
101   private:
102     // Helper class for handling events.
103     // The usage here is const safe.
104     class TimeCheckHandler {
105     public:
106         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)107         TimeCheckHandler(S&& _tag, F&& _onTimer, bool _crashOnTimeout,
108             Duration _timeoutDuration, Duration _secondChanceDuration,
109             std::chrono::system_clock::time_point _startSystemTime,
110             pid_t _tid)
111             : tag(std::forward<S>(_tag))
112             , onTimer(std::forward<F>(_onTimer))
113             , crashOnTimeout(_crashOnTimeout)
114             , timeoutDuration(_timeoutDuration)
115             , secondChanceDuration(_secondChanceDuration)
116             , startSystemTime(_startSystemTime)
117             , tid(_tid)
118             {}
119         const FixedString62 tag;
120         const OnTimerFunc onTimer;
121         const bool crashOnTimeout;
122         const Duration timeoutDuration;
123         const Duration secondChanceDuration;
124         const std::chrono::system_clock::time_point startSystemTime;
125         const pid_t tid;
126 
127         void onCancel(TimerThread::Handle handle) const;
128         void onTimeout(TimerThread::Handle handle) const;
129     };
130 
131     // Returns a string that represents the timeout vs elapsed time,
132     // and diagnostics if there are any potential issues.
133     static std::string analyzeTimeouts(
134             float timeoutMs, float elapsedSteadyMs, float elapsedSystemMs);
135 
136     static TimerThread& getTimeCheckThread();
137     static void accessAudioHalPids(std::vector<pid_t>* pids, bool update);
138 
139     // mTimeCheckHandler is immutable, prefer to be first initialized, last destroyed.
140     // Technically speaking, we do not need a shared_ptr here because TimerThread::cancelTask()
141     // is mutually exclusive of the callback, but the price paid for lifetime safety is minimal.
142     const std::shared_ptr<const TimeCheckHandler> mTimeCheckHandler;
143     const TimerThread::Handle mTimerHandle = TimerThread::INVALID_HANDLE;
144 };
145 
146 // Returns a TimeCheck object that sends info to MethodStatistics
147 // obtained from getStatisticsForClass(className).
148 TimeCheck makeTimeCheckStatsForClassMethod(
149         std::string_view className, std::string_view methodName);
150 
151 }  // namespace android::mediautils
152