xref: /aosp_15_r20/frameworks/av/media/utils/TimeCheck.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker #include <csignal>
18*ec779b8eSAndroid Build Coastguard Worker #include "mediautils/TimerThread.h"
19*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "TimeCheck"
20*ec779b8eSAndroid Build Coastguard Worker 
21*ec779b8eSAndroid Build Coastguard Worker #include <optional>
22*ec779b8eSAndroid Build Coastguard Worker 
23*ec779b8eSAndroid Build Coastguard Worker #include <android-base/logging.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <android-base/strings.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/clock.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <cutils/properties.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <mediautils/EventLog.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <mediautils/FixedString.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <mediautils/MethodStatistics.h>
30*ec779b8eSAndroid Build Coastguard Worker #include <mediautils/TimeCheck.h>
31*ec779b8eSAndroid Build Coastguard Worker #include <mediautils/TidWrapper.h>
32*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
33*ec779b8eSAndroid Build Coastguard Worker 
34*ec779b8eSAndroid Build Coastguard Worker #if defined(__ANDROID__)
35*ec779b8eSAndroid Build Coastguard Worker #include "debuggerd/handler.h"
36*ec779b8eSAndroid Build Coastguard Worker #endif
37*ec779b8eSAndroid Build Coastguard Worker 
38*ec779b8eSAndroid Build Coastguard Worker 
39*ec779b8eSAndroid Build Coastguard Worker namespace android::mediautils {
40*ec779b8eSAndroid Build Coastguard Worker 
41*ec779b8eSAndroid Build Coastguard Worker // Note: The sum of kDefaultTimeOutDurationMs and kDefaultSecondChanceDurationMs
42*ec779b8eSAndroid Build Coastguard Worker // should be no less than 2 seconds, otherwise spurious timeouts
43*ec779b8eSAndroid Build Coastguard Worker // may occur with system suspend.
44*ec779b8eSAndroid Build Coastguard Worker static constexpr int kDefaultTimeoutDurationMs = 3000;
45*ec779b8eSAndroid Build Coastguard Worker 
46*ec779b8eSAndroid Build Coastguard Worker // Due to suspend abort not incrementing the monotonic clock,
47*ec779b8eSAndroid Build Coastguard Worker // we allow another second chance timeout after the first timeout expires.
48*ec779b8eSAndroid Build Coastguard Worker //
49*ec779b8eSAndroid Build Coastguard Worker // The total timeout is therefore kDefaultTimeoutDuration + kDefaultSecondChanceDuration,
50*ec779b8eSAndroid Build Coastguard Worker // and the result is more stable when the monotonic clock increments during suspend.
51*ec779b8eSAndroid Build Coastguard Worker //
52*ec779b8eSAndroid Build Coastguard Worker static constexpr int kDefaultSecondChanceDurationMs = 2000;
53*ec779b8eSAndroid Build Coastguard Worker 
54*ec779b8eSAndroid Build Coastguard Worker /* static */
getDefaultTimeoutDuration()55*ec779b8eSAndroid Build Coastguard Worker TimeCheck::Duration TimeCheck::getDefaultTimeoutDuration() {
56*ec779b8eSAndroid Build Coastguard Worker     static constinit std::atomic<int> defaultTimeoutDurationMs{};
57*ec779b8eSAndroid Build Coastguard Worker     auto defaultMs = defaultTimeoutDurationMs.load(std::memory_order_relaxed);
58*ec779b8eSAndroid Build Coastguard Worker     if (defaultMs == 0) {
59*ec779b8eSAndroid Build Coastguard Worker         defaultMs = property_get_int32(
60*ec779b8eSAndroid Build Coastguard Worker                 "audio.timecheck.timeout_duration_ms", kDefaultTimeoutDurationMs);
61*ec779b8eSAndroid Build Coastguard Worker         if (defaultMs < 1) defaultMs = kDefaultTimeoutDurationMs;
62*ec779b8eSAndroid Build Coastguard Worker         defaultTimeoutDurationMs.store(defaultMs, std::memory_order_relaxed);
63*ec779b8eSAndroid Build Coastguard Worker     }
64*ec779b8eSAndroid Build Coastguard Worker     return std::chrono::milliseconds(defaultMs);
65*ec779b8eSAndroid Build Coastguard Worker }
66*ec779b8eSAndroid Build Coastguard Worker 
67*ec779b8eSAndroid Build Coastguard Worker /* static */
getDefaultSecondChanceDuration()68*ec779b8eSAndroid Build Coastguard Worker TimeCheck::Duration TimeCheck::getDefaultSecondChanceDuration() {
69*ec779b8eSAndroid Build Coastguard Worker     static constinit std::atomic<int> defaultSecondChanceDurationMs{};
70*ec779b8eSAndroid Build Coastguard Worker     auto defaultMs = defaultSecondChanceDurationMs.load(std::memory_order_relaxed);
71*ec779b8eSAndroid Build Coastguard Worker     if (defaultMs == 0) {
72*ec779b8eSAndroid Build Coastguard Worker         defaultMs = property_get_int32(
73*ec779b8eSAndroid Build Coastguard Worker                 "audio.timecheck.second_chance_duration_ms", kDefaultSecondChanceDurationMs);
74*ec779b8eSAndroid Build Coastguard Worker         if (defaultMs < 1) defaultMs = kDefaultSecondChanceDurationMs;
75*ec779b8eSAndroid Build Coastguard Worker         defaultSecondChanceDurationMs.store(defaultMs, std::memory_order_relaxed);
76*ec779b8eSAndroid Build Coastguard Worker     }
77*ec779b8eSAndroid Build Coastguard Worker     return std::chrono::milliseconds(defaultMs);
78*ec779b8eSAndroid Build Coastguard Worker }
79*ec779b8eSAndroid Build Coastguard Worker 
80*ec779b8eSAndroid Build Coastguard Worker // This function appropriately signals a pid to dump a backtrace if we are
81*ec779b8eSAndroid Build Coastguard Worker // running on device (and the HAL exists). If we are not running on an Android
82*ec779b8eSAndroid Build Coastguard Worker // device, there is no HAL to signal (so we do nothing).
signalAudioHAL(pid_t pid)83*ec779b8eSAndroid Build Coastguard Worker static inline void signalAudioHAL([[maybe_unused]] pid_t pid) {
84*ec779b8eSAndroid Build Coastguard Worker #if defined(__ANDROID__)
85*ec779b8eSAndroid Build Coastguard Worker     sigqueue(pid, DEBUGGER_SIGNAL, {.sival_int = 0});
86*ec779b8eSAndroid Build Coastguard Worker #endif
87*ec779b8eSAndroid Build Coastguard Worker }
88*ec779b8eSAndroid Build Coastguard Worker 
89*ec779b8eSAndroid Build Coastguard Worker /**
90*ec779b8eSAndroid Build Coastguard Worker  * Returns the std::string "HH:MM:SS.MSc" from a system_clock time_point.
91*ec779b8eSAndroid Build Coastguard Worker  */
formatTime(std::chrono::system_clock::time_point t)92*ec779b8eSAndroid Build Coastguard Worker std::string formatTime(std::chrono::system_clock::time_point t) {
93*ec779b8eSAndroid Build Coastguard Worker     auto time_string = audio_utils_time_string_from_ns(
94*ec779b8eSAndroid Build Coastguard Worker             std::chrono::nanoseconds(t.time_since_epoch()).count());
95*ec779b8eSAndroid Build Coastguard Worker 
96*ec779b8eSAndroid Build Coastguard Worker     // The time string is 19 characters (including null termination).
97*ec779b8eSAndroid Build Coastguard Worker     // Example: "03-27 16:47:06.187"
98*ec779b8eSAndroid Build Coastguard Worker     //           MM DD HH MM SS MS
99*ec779b8eSAndroid Build Coastguard Worker     // We offset by 6 to get HH:MM:SS.MSc
100*ec779b8eSAndroid Build Coastguard Worker     //
101*ec779b8eSAndroid Build Coastguard Worker     return time_string.time + 6; // offset to remove month/day.
102*ec779b8eSAndroid Build Coastguard Worker }
103*ec779b8eSAndroid Build Coastguard Worker 
104*ec779b8eSAndroid Build Coastguard Worker /**
105*ec779b8eSAndroid Build Coastguard Worker  * Finds the end of the common time prefix.
106*ec779b8eSAndroid Build Coastguard Worker  *
107*ec779b8eSAndroid Build Coastguard Worker  * This is as an option to remove the common time prefix to avoid
108*ec779b8eSAndroid Build Coastguard Worker  * unnecessary duplicated strings.
109*ec779b8eSAndroid Build Coastguard Worker  *
110*ec779b8eSAndroid Build Coastguard Worker  * \param time1 a time string
111*ec779b8eSAndroid Build Coastguard Worker  * \param time2 a time string
112*ec779b8eSAndroid Build Coastguard Worker  * \return      the position where the common time prefix ends. For abbreviated
113*ec779b8eSAndroid Build Coastguard Worker  *              printing of time2, offset the character pointer by this position.
114*ec779b8eSAndroid Build Coastguard Worker  */
commonTimePrefixPosition(std::string_view time1,std::string_view time2)115*ec779b8eSAndroid Build Coastguard Worker static size_t commonTimePrefixPosition(std::string_view time1, std::string_view time2) {
116*ec779b8eSAndroid Build Coastguard Worker     const size_t endPos = std::min(time1.size(), time2.size());
117*ec779b8eSAndroid Build Coastguard Worker     size_t i;
118*ec779b8eSAndroid Build Coastguard Worker 
119*ec779b8eSAndroid Build Coastguard Worker     // Find location of the first mismatch between strings
120*ec779b8eSAndroid Build Coastguard Worker     for (i = 0; ; ++i) {
121*ec779b8eSAndroid Build Coastguard Worker         if (i == endPos) {
122*ec779b8eSAndroid Build Coastguard Worker             return i; // strings match completely to the length of one of the strings.
123*ec779b8eSAndroid Build Coastguard Worker         }
124*ec779b8eSAndroid Build Coastguard Worker         if (time1[i] != time2[i]) {
125*ec779b8eSAndroid Build Coastguard Worker             break;
126*ec779b8eSAndroid Build Coastguard Worker         }
127*ec779b8eSAndroid Build Coastguard Worker         if (time1[i] == '\0') {
128*ec779b8eSAndroid Build Coastguard Worker             return i; // "printed" strings match completely.  No need to check further.
129*ec779b8eSAndroid Build Coastguard Worker         }
130*ec779b8eSAndroid Build Coastguard Worker     }
131*ec779b8eSAndroid Build Coastguard Worker 
132*ec779b8eSAndroid Build Coastguard Worker     // Go backwards until we find a delimeter or space.
133*ec779b8eSAndroid Build Coastguard Worker     for (; i > 0
134*ec779b8eSAndroid Build Coastguard Worker            && isdigit(time1[i]) // still a number
135*ec779b8eSAndroid Build Coastguard Worker            && time1[i - 1] != ' '
136*ec779b8eSAndroid Build Coastguard Worker          ; --i) {
137*ec779b8eSAndroid Build Coastguard Worker     }
138*ec779b8eSAndroid Build Coastguard Worker     return i;
139*ec779b8eSAndroid Build Coastguard Worker }
140*ec779b8eSAndroid Build Coastguard Worker 
141*ec779b8eSAndroid Build Coastguard Worker /**
142*ec779b8eSAndroid Build Coastguard Worker  * Returns the unique suffix of time2 that isn't present in time1.
143*ec779b8eSAndroid Build Coastguard Worker  *
144*ec779b8eSAndroid Build Coastguard Worker  * If time2 is identical to time1, then an empty string_view is returned.
145*ec779b8eSAndroid Build Coastguard Worker  * This method is used to elide the common prefix when printing times.
146*ec779b8eSAndroid Build Coastguard Worker  */
timeSuffix(std::string_view time1,std::string_view time2)147*ec779b8eSAndroid Build Coastguard Worker std::string_view timeSuffix(std::string_view time1, std::string_view time2) {
148*ec779b8eSAndroid Build Coastguard Worker     const size_t pos = commonTimePrefixPosition(time1, time2);
149*ec779b8eSAndroid Build Coastguard Worker     return time2.substr(pos);
150*ec779b8eSAndroid Build Coastguard Worker }
151*ec779b8eSAndroid Build Coastguard Worker 
152*ec779b8eSAndroid Build Coastguard Worker // Audio HAL server pids vector used to generate audio HAL processes tombstone
153*ec779b8eSAndroid Build Coastguard Worker // when audioserver watchdog triggers.
154*ec779b8eSAndroid Build Coastguard Worker // We use a lockless storage to avoid potential deadlocks in the context of watchdog
155*ec779b8eSAndroid Build Coastguard Worker // trigger.
156*ec779b8eSAndroid Build Coastguard Worker // Protection again simultaneous writes is not needed given one update takes place
157*ec779b8eSAndroid Build Coastguard Worker // during AudioFlinger construction and other comes necessarily later once the IAudioFlinger
158*ec779b8eSAndroid Build Coastguard Worker // interface is available.
159*ec779b8eSAndroid Build Coastguard Worker // The use of an atomic index just guaranties that current vector is fully initialized
160*ec779b8eSAndroid Build Coastguard Worker // when read.
161*ec779b8eSAndroid Build Coastguard Worker /* static */
accessAudioHalPids(std::vector<pid_t> * pids,bool update)162*ec779b8eSAndroid Build Coastguard Worker void TimeCheck::accessAudioHalPids(std::vector<pid_t>* pids, bool update) {
163*ec779b8eSAndroid Build Coastguard Worker     static constexpr int kNumAudioHalPidsVectors = 3;
164*ec779b8eSAndroid Build Coastguard Worker     static std::vector<pid_t> audioHalPids[kNumAudioHalPidsVectors];
165*ec779b8eSAndroid Build Coastguard Worker     static std::atomic<unsigned> curAudioHalPids = 0;
166*ec779b8eSAndroid Build Coastguard Worker 
167*ec779b8eSAndroid Build Coastguard Worker     if (update) {
168*ec779b8eSAndroid Build Coastguard Worker         audioHalPids[(curAudioHalPids++ + 1) % kNumAudioHalPidsVectors] = *pids;
169*ec779b8eSAndroid Build Coastguard Worker     } else {
170*ec779b8eSAndroid Build Coastguard Worker         *pids = audioHalPids[curAudioHalPids % kNumAudioHalPidsVectors];
171*ec779b8eSAndroid Build Coastguard Worker     }
172*ec779b8eSAndroid Build Coastguard Worker }
173*ec779b8eSAndroid Build Coastguard Worker 
174*ec779b8eSAndroid Build Coastguard Worker /* static */
setAudioHalPids(const std::vector<pid_t> & pids)175*ec779b8eSAndroid Build Coastguard Worker void TimeCheck::setAudioHalPids(const std::vector<pid_t>& pids) {
176*ec779b8eSAndroid Build Coastguard Worker     accessAudioHalPids(&(const_cast<std::vector<pid_t>&>(pids)), true);
177*ec779b8eSAndroid Build Coastguard Worker }
178*ec779b8eSAndroid Build Coastguard Worker 
179*ec779b8eSAndroid Build Coastguard Worker /* static */
getAudioHalPids()180*ec779b8eSAndroid Build Coastguard Worker std::vector<pid_t> TimeCheck::getAudioHalPids() {
181*ec779b8eSAndroid Build Coastguard Worker     std::vector<pid_t> pids;
182*ec779b8eSAndroid Build Coastguard Worker     accessAudioHalPids(&pids, false);
183*ec779b8eSAndroid Build Coastguard Worker     return pids;
184*ec779b8eSAndroid Build Coastguard Worker }
185*ec779b8eSAndroid Build Coastguard Worker 
186*ec779b8eSAndroid Build Coastguard Worker /* static */
signalAudioHals()187*ec779b8eSAndroid Build Coastguard Worker std::string TimeCheck::signalAudioHals() {
188*ec779b8eSAndroid Build Coastguard Worker     std::vector<pid_t> pids = getAudioHalPids();
189*ec779b8eSAndroid Build Coastguard Worker     std::string halPids;
190*ec779b8eSAndroid Build Coastguard Worker     if (pids.size() != 0) {
191*ec779b8eSAndroid Build Coastguard Worker         for (const auto& pid : pids) {
192*ec779b8eSAndroid Build Coastguard Worker             ALOGI("requesting tombstone for pid: %d", pid);
193*ec779b8eSAndroid Build Coastguard Worker             halPids.append(std::to_string(pid)).append(" ");
194*ec779b8eSAndroid Build Coastguard Worker             signalAudioHAL(pid);
195*ec779b8eSAndroid Build Coastguard Worker         }
196*ec779b8eSAndroid Build Coastguard Worker         // Allow time to complete, usually the caller is forcing restart afterwards.
197*ec779b8eSAndroid Build Coastguard Worker         sleep(1);
198*ec779b8eSAndroid Build Coastguard Worker     }
199*ec779b8eSAndroid Build Coastguard Worker     return halPids;
200*ec779b8eSAndroid Build Coastguard Worker }
201*ec779b8eSAndroid Build Coastguard Worker 
202*ec779b8eSAndroid Build Coastguard Worker /* static */
getTimeCheckThread()203*ec779b8eSAndroid Build Coastguard Worker TimerThread& TimeCheck::getTimeCheckThread() {
204*ec779b8eSAndroid Build Coastguard Worker     static TimerThread sTimeCheckThread{};
205*ec779b8eSAndroid Build Coastguard Worker     return sTimeCheckThread;
206*ec779b8eSAndroid Build Coastguard Worker }
207*ec779b8eSAndroid Build Coastguard Worker 
208*ec779b8eSAndroid Build Coastguard Worker /* static */
toString()209*ec779b8eSAndroid Build Coastguard Worker std::string TimeCheck::toString() {
210*ec779b8eSAndroid Build Coastguard Worker     // note pending and retired are individually locked for maximum concurrency,
211*ec779b8eSAndroid Build Coastguard Worker     // snapshot is not instantaneous at a single time.
212*ec779b8eSAndroid Build Coastguard Worker     return getTimeCheckThread().getSnapshotAnalysis().toString();
213*ec779b8eSAndroid Build Coastguard Worker }
214*ec779b8eSAndroid Build Coastguard Worker 
TimeCheck(std::string_view tag,OnTimerFunc && onTimer,Duration requestedTimeoutDuration,Duration secondChanceDuration,bool crashOnTimeout)215*ec779b8eSAndroid Build Coastguard Worker TimeCheck::TimeCheck(std::string_view tag, OnTimerFunc&& onTimer, Duration requestedTimeoutDuration,
216*ec779b8eSAndroid Build Coastguard Worker         Duration secondChanceDuration, bool crashOnTimeout)
217*ec779b8eSAndroid Build Coastguard Worker     : mTimeCheckHandler{ std::make_shared<TimeCheckHandler>(
218*ec779b8eSAndroid Build Coastguard Worker             tag, std::move(onTimer), crashOnTimeout, requestedTimeoutDuration,
219*ec779b8eSAndroid Build Coastguard Worker             secondChanceDuration, std::chrono::system_clock::now(), getThreadIdWrapper()) }
220*ec779b8eSAndroid Build Coastguard Worker     , mTimerHandle(requestedTimeoutDuration.count() == 0
221*ec779b8eSAndroid Build Coastguard Worker               /* for TimeCheck we don't consider a non-zero secondChanceDuration here */
222*ec779b8eSAndroid Build Coastguard Worker               ? getTimeCheckThread().trackTask(mTimeCheckHandler->tag)
223*ec779b8eSAndroid Build Coastguard Worker               : getTimeCheckThread().scheduleTask(
224*ec779b8eSAndroid Build Coastguard Worker                       mTimeCheckHandler->tag,
225*ec779b8eSAndroid Build Coastguard Worker                       // Pass in all the arguments by value to this task for safety.
226*ec779b8eSAndroid Build Coastguard Worker                       // The thread could call the callback before the constructor is finished.
227*ec779b8eSAndroid Build Coastguard Worker                       // The destructor is not blocked on callback.
__anon2392a1780102(TimerThread::Handle timerHandle) 228*ec779b8eSAndroid Build Coastguard Worker                       [ timeCheckHandler = mTimeCheckHandler ](TimerThread::Handle timerHandle) {
229*ec779b8eSAndroid Build Coastguard Worker                           timeCheckHandler->onTimeout(timerHandle);
230*ec779b8eSAndroid Build Coastguard Worker                       },
231*ec779b8eSAndroid Build Coastguard Worker                       requestedTimeoutDuration,
232*ec779b8eSAndroid Build Coastguard Worker                       secondChanceDuration)) {}
233*ec779b8eSAndroid Build Coastguard Worker 
~TimeCheck()234*ec779b8eSAndroid Build Coastguard Worker TimeCheck::~TimeCheck() {
235*ec779b8eSAndroid Build Coastguard Worker     if (mTimeCheckHandler) {
236*ec779b8eSAndroid Build Coastguard Worker         mTimeCheckHandler->onCancel(mTimerHandle);
237*ec779b8eSAndroid Build Coastguard Worker     }
238*ec779b8eSAndroid Build Coastguard Worker }
239*ec779b8eSAndroid Build Coastguard Worker 
240*ec779b8eSAndroid Build Coastguard Worker /* static */
analyzeTimeouts(float requestedTimeoutMs,float secondChanceMs,float elapsedSteadyMs,float elapsedSystemMs)241*ec779b8eSAndroid Build Coastguard Worker std::string TimeCheck::analyzeTimeouts(
242*ec779b8eSAndroid Build Coastguard Worker         float requestedTimeoutMs, float secondChanceMs,
243*ec779b8eSAndroid Build Coastguard Worker         float elapsedSteadyMs, float elapsedSystemMs) {
244*ec779b8eSAndroid Build Coastguard Worker     // Track any OS clock issues with suspend.
245*ec779b8eSAndroid Build Coastguard Worker     // It is possible that the elapsedSystemMs is much greater than elapsedSteadyMs if
246*ec779b8eSAndroid Build Coastguard Worker     // a suspend occurs; however, we always expect the timeout ms should always be slightly
247*ec779b8eSAndroid Build Coastguard Worker     // less than the elapsed steady ms regardless of whether a suspend occurs or not.
248*ec779b8eSAndroid Build Coastguard Worker 
249*ec779b8eSAndroid Build Coastguard Worker     const float totalTimeoutMs = requestedTimeoutMs + secondChanceMs;
250*ec779b8eSAndroid Build Coastguard Worker     std::string s = std::format(
251*ec779b8eSAndroid Build Coastguard Worker             "Timeout ms {:.2f} ({:.2f} + {:.2f})"
252*ec779b8eSAndroid Build Coastguard Worker             " elapsed steady ms {:.4f} elapsed system ms {:.4f}",
253*ec779b8eSAndroid Build Coastguard Worker             totalTimeoutMs, requestedTimeoutMs, secondChanceMs, elapsedSteadyMs, elapsedSystemMs);
254*ec779b8eSAndroid Build Coastguard Worker 
255*ec779b8eSAndroid Build Coastguard Worker     // Is there something unusual?
256*ec779b8eSAndroid Build Coastguard Worker     static constexpr float TOLERANCE_CONTEXT_SWITCH_MS = 200.f;
257*ec779b8eSAndroid Build Coastguard Worker 
258*ec779b8eSAndroid Build Coastguard Worker     if (totalTimeoutMs > elapsedSteadyMs || totalTimeoutMs > elapsedSystemMs) {
259*ec779b8eSAndroid Build Coastguard Worker         s.append("\nError: early expiration - "
260*ec779b8eSAndroid Build Coastguard Worker                 "totalTimeoutMs should be less than elapsed time");
261*ec779b8eSAndroid Build Coastguard Worker     }
262*ec779b8eSAndroid Build Coastguard Worker 
263*ec779b8eSAndroid Build Coastguard Worker     if (elapsedSteadyMs > elapsedSystemMs + TOLERANCE_CONTEXT_SWITCH_MS) {
264*ec779b8eSAndroid Build Coastguard Worker         s.append("\nWarning: steady time should not advance faster than system time");
265*ec779b8eSAndroid Build Coastguard Worker     }
266*ec779b8eSAndroid Build Coastguard Worker 
267*ec779b8eSAndroid Build Coastguard Worker     // This has been found in suspend stress testing.
268*ec779b8eSAndroid Build Coastguard Worker     if (elapsedSteadyMs > totalTimeoutMs + TOLERANCE_CONTEXT_SWITCH_MS) {
269*ec779b8eSAndroid Build Coastguard Worker         s.append("\nWarning: steady time significantly exceeds timeout "
270*ec779b8eSAndroid Build Coastguard Worker                 "- possible thread stall or aborted suspend");
271*ec779b8eSAndroid Build Coastguard Worker     }
272*ec779b8eSAndroid Build Coastguard Worker 
273*ec779b8eSAndroid Build Coastguard Worker     // This has been found in suspend stress testing.
274*ec779b8eSAndroid Build Coastguard Worker     if (elapsedSystemMs > totalTimeoutMs + TOLERANCE_CONTEXT_SWITCH_MS) {
275*ec779b8eSAndroid Build Coastguard Worker         s.append("\nInformation: system time significantly exceeds timeout "
276*ec779b8eSAndroid Build Coastguard Worker                 "- possible suspend");
277*ec779b8eSAndroid Build Coastguard Worker     }
278*ec779b8eSAndroid Build Coastguard Worker     return s;
279*ec779b8eSAndroid Build Coastguard Worker }
280*ec779b8eSAndroid Build Coastguard Worker 
281*ec779b8eSAndroid Build Coastguard Worker // To avoid any potential race conditions, the timer handle
282*ec779b8eSAndroid Build Coastguard Worker // (expiration = clock steady start + timeout) is passed into the callback.
onCancel(TimerThread::Handle timerHandle) const283*ec779b8eSAndroid Build Coastguard Worker void TimeCheck::TimeCheckHandler::onCancel(TimerThread::Handle timerHandle) const
284*ec779b8eSAndroid Build Coastguard Worker {
285*ec779b8eSAndroid Build Coastguard Worker     if (TimeCheck::getTimeCheckThread().cancelTask(timerHandle) && onTimer) {
286*ec779b8eSAndroid Build Coastguard Worker         const std::chrono::steady_clock::time_point endSteadyTime =
287*ec779b8eSAndroid Build Coastguard Worker                 std::chrono::steady_clock::now();
288*ec779b8eSAndroid Build Coastguard Worker         const float elapsedSteadyMs = std::chrono::duration_cast<FloatMs>(
289*ec779b8eSAndroid Build Coastguard Worker                 endSteadyTime - timerHandle + timeoutDuration).count();
290*ec779b8eSAndroid Build Coastguard Worker         // send the elapsed steady time for statistics.
291*ec779b8eSAndroid Build Coastguard Worker         onTimer(false /* timeout */, elapsedSteadyMs);
292*ec779b8eSAndroid Build Coastguard Worker     }
293*ec779b8eSAndroid Build Coastguard Worker }
294*ec779b8eSAndroid Build Coastguard Worker 
295*ec779b8eSAndroid Build Coastguard Worker // To avoid any potential race conditions, the timer handle
296*ec779b8eSAndroid Build Coastguard Worker // (expiration = clock steady start + timeout) is passed into the callback.
onTimeout(TimerThread::Handle timerHandle) const297*ec779b8eSAndroid Build Coastguard Worker void TimeCheck::TimeCheckHandler::onTimeout(TimerThread::Handle timerHandle) const
298*ec779b8eSAndroid Build Coastguard Worker {
299*ec779b8eSAndroid Build Coastguard Worker     const std::chrono::steady_clock::time_point endSteadyTime = std::chrono::steady_clock::now();
300*ec779b8eSAndroid Build Coastguard Worker     const std::chrono::system_clock::time_point endSystemTime = std::chrono::system_clock::now();
301*ec779b8eSAndroid Build Coastguard Worker     // timerHandle incorporates the timeout
302*ec779b8eSAndroid Build Coastguard Worker     const float elapsedSteadyMs = std::chrono::duration_cast<FloatMs>(
303*ec779b8eSAndroid Build Coastguard Worker             endSteadyTime - (timerHandle - timeoutDuration)).count();
304*ec779b8eSAndroid Build Coastguard Worker     const float elapsedSystemMs = std::chrono::duration_cast<FloatMs>(
305*ec779b8eSAndroid Build Coastguard Worker             endSystemTime - startSystemTime).count();
306*ec779b8eSAndroid Build Coastguard Worker     const float requestedTimeoutMs = std::chrono::duration_cast<FloatMs>(
307*ec779b8eSAndroid Build Coastguard Worker             timeoutDuration).count();
308*ec779b8eSAndroid Build Coastguard Worker     const float secondChanceMs = std::chrono::duration_cast<FloatMs>(
309*ec779b8eSAndroid Build Coastguard Worker             secondChanceDuration).count();
310*ec779b8eSAndroid Build Coastguard Worker 
311*ec779b8eSAndroid Build Coastguard Worker     if (onTimer) {
312*ec779b8eSAndroid Build Coastguard Worker         onTimer(true /* timeout */, elapsedSteadyMs);
313*ec779b8eSAndroid Build Coastguard Worker     }
314*ec779b8eSAndroid Build Coastguard Worker 
315*ec779b8eSAndroid Build Coastguard Worker     if (!crashOnTimeout) return;
316*ec779b8eSAndroid Build Coastguard Worker 
317*ec779b8eSAndroid Build Coastguard Worker     // Generate the TimerThread summary string early before sending signals to the
318*ec779b8eSAndroid Build Coastguard Worker     // HAL processes which can affect thread behavior.
319*ec779b8eSAndroid Build Coastguard Worker     const auto snapshotAnalysis = getTimeCheckThread().getSnapshotAnalysis(4 /* retiredCount */);
320*ec779b8eSAndroid Build Coastguard Worker 
321*ec779b8eSAndroid Build Coastguard Worker     // Generate audio HAL processes tombstones.
322*ec779b8eSAndroid Build Coastguard Worker     std::string halPids = signalAudioHals();
323*ec779b8eSAndroid Build Coastguard Worker     if (!halPids.empty()) {
324*ec779b8eSAndroid Build Coastguard Worker         halPids = "HAL pids [ " + halPids + "]";
325*ec779b8eSAndroid Build Coastguard Worker     } else {
326*ec779b8eSAndroid Build Coastguard Worker         halPids = "No HAL process pids available";
327*ec779b8eSAndroid Build Coastguard Worker         ALOGI("%s", (halPids + ", skipping tombstones").c_str());
328*ec779b8eSAndroid Build Coastguard Worker     }
329*ec779b8eSAndroid Build Coastguard Worker 
330*ec779b8eSAndroid Build Coastguard Worker     LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag.c_str());
331*ec779b8eSAndroid Build Coastguard Worker 
332*ec779b8eSAndroid Build Coastguard Worker     // Create abort message string - caution: this can be very large.
333*ec779b8eSAndroid Build Coastguard Worker     const std::string abortMessage = std::string("TimeCheck timeout for ")
334*ec779b8eSAndroid Build Coastguard Worker             .append(tag)
335*ec779b8eSAndroid Build Coastguard Worker             .append(" scheduled ").append(formatTime(startSystemTime))
336*ec779b8eSAndroid Build Coastguard Worker             .append(" on thread ").append(std::to_string(tid)).append("\n")
337*ec779b8eSAndroid Build Coastguard Worker             .append(analyzeTimeouts(requestedTimeoutMs, secondChanceMs,
338*ec779b8eSAndroid Build Coastguard Worker                     elapsedSteadyMs, elapsedSystemMs)).append("\n")
339*ec779b8eSAndroid Build Coastguard Worker             .append(halPids).append("\n")
340*ec779b8eSAndroid Build Coastguard Worker             .append(snapshotAnalysis.toString());
341*ec779b8eSAndroid Build Coastguard Worker 
342*ec779b8eSAndroid Build Coastguard Worker     // In many cases, the initial timeout stack differs from the abort backtrace because
343*ec779b8eSAndroid Build Coastguard Worker     // (1) the time difference between initial timeout and the final abort signal
344*ec779b8eSAndroid Build Coastguard Worker     // and (2) signalling the HAL audio service may cause
345*ec779b8eSAndroid Build Coastguard Worker     // the thread to unblock and continue.
346*ec779b8eSAndroid Build Coastguard Worker 
347*ec779b8eSAndroid Build Coastguard Worker     // Note: LOG_ALWAYS_FATAL limits the size of the string - per log/log.h:
348*ec779b8eSAndroid Build Coastguard Worker     // Log message text may be truncated to less than an
349*ec779b8eSAndroid Build Coastguard Worker     // implementation-specific limit (1023 bytes).
350*ec779b8eSAndroid Build Coastguard Worker     //
351*ec779b8eSAndroid Build Coastguard Worker     // Here, we send the string through android-base/logging.h LOG()
352*ec779b8eSAndroid Build Coastguard Worker     // to avoid the size limitation. LOG(FATAL) does an abort whereas
353*ec779b8eSAndroid Build Coastguard Worker     // LOG(FATAL_WITHOUT_ABORT) does not abort.
354*ec779b8eSAndroid Build Coastguard Worker 
355*ec779b8eSAndroid Build Coastguard Worker     static constexpr pid_t invalidPid = TimerThread::SnapshotAnalysis::INVALID_PID;
356*ec779b8eSAndroid Build Coastguard Worker     pid_t tidToAbort = invalidPid;
357*ec779b8eSAndroid Build Coastguard Worker     if (snapshotAnalysis.suspectTid != invalidPid) {
358*ec779b8eSAndroid Build Coastguard Worker         tidToAbort = snapshotAnalysis.suspectTid;
359*ec779b8eSAndroid Build Coastguard Worker     } else if (snapshotAnalysis.timeoutTid != invalidPid) {
360*ec779b8eSAndroid Build Coastguard Worker         tidToAbort = snapshotAnalysis.timeoutTid;
361*ec779b8eSAndroid Build Coastguard Worker     }
362*ec779b8eSAndroid Build Coastguard Worker 
363*ec779b8eSAndroid Build Coastguard Worker     LOG(FATAL_WITHOUT_ABORT) << abortMessage;
364*ec779b8eSAndroid Build Coastguard Worker     const auto ret = abortTid(tidToAbort);
365*ec779b8eSAndroid Build Coastguard Worker     if (ret < 0) {
366*ec779b8eSAndroid Build Coastguard Worker         LOG(FATAL) << "TimeCheck thread signal failed, aborting process. "
367*ec779b8eSAndroid Build Coastguard Worker                        "errno: " << errno << base::ErrnoNumberAsString(errno);
368*ec779b8eSAndroid Build Coastguard Worker     }
369*ec779b8eSAndroid Build Coastguard Worker }
370*ec779b8eSAndroid Build Coastguard Worker 
371*ec779b8eSAndroid Build Coastguard Worker // Automatically create a TimeCheck class for a class and method.
372*ec779b8eSAndroid Build Coastguard Worker // This is used for Audio HAL support.
makeTimeCheckStatsForClassMethod(std::string_view className,std::string_view methodName)373*ec779b8eSAndroid Build Coastguard Worker mediautils::TimeCheck makeTimeCheckStatsForClassMethod(
374*ec779b8eSAndroid Build Coastguard Worker         std::string_view className, std::string_view methodName) {
375*ec779b8eSAndroid Build Coastguard Worker     std::shared_ptr<MethodStatistics<std::string>> statistics =
376*ec779b8eSAndroid Build Coastguard Worker             mediautils::getStatisticsForClass(className);
377*ec779b8eSAndroid Build Coastguard Worker     if (!statistics) return {}; // empty TimeCheck.
378*ec779b8eSAndroid Build Coastguard Worker     return mediautils::TimeCheck(
379*ec779b8eSAndroid Build Coastguard Worker             FixedString62(className).append("::").append(methodName),
380*ec779b8eSAndroid Build Coastguard Worker             [ safeMethodName = FixedString30(methodName),
381*ec779b8eSAndroid Build Coastguard Worker               stats = std::move(statistics) ]
382*ec779b8eSAndroid Build Coastguard Worker             (bool timeout, float elapsedMs) {
383*ec779b8eSAndroid Build Coastguard Worker                     if (timeout) {
384*ec779b8eSAndroid Build Coastguard Worker                         ; // ignored, there is no timeout value.
385*ec779b8eSAndroid Build Coastguard Worker                     } else {
386*ec779b8eSAndroid Build Coastguard Worker                         stats->event(safeMethodName.asStringView(), elapsedMs);
387*ec779b8eSAndroid Build Coastguard Worker                     }
388*ec779b8eSAndroid Build Coastguard Worker             }, {} /* timeoutDuration */, {} /* secondChanceDuration */, false /* crashOnTimeout */);
389*ec779b8eSAndroid Build Coastguard Worker }
390*ec779b8eSAndroid Build Coastguard Worker 
391*ec779b8eSAndroid Build Coastguard Worker }  // namespace android::mediautils
392