blob: e53d70f60d2cbb055d837d20c79c3ca92bf42e53 [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
Eric Laurent42896a02019-09-27 15:40:33 -070017#define LOG_TAG "TimeCheck"
Eric Laurent3528c932018-02-23 17:17:22 -080018
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080019#include <optional>
20
Andy Hung10ac7112022-03-28 08:00:40 -070021#include <android-base/logging.h>
Andy Hunga2a1ac32022-03-18 16:12:11 -070022#include <audio_utils/clock.h>
Marco Nelissencf90b492019-09-26 11:20:54 -070023#include <mediautils/EventLog.h>
Andy Hung35f96152022-07-15 15:18:59 -070024#include <mediautils/FixedString.h>
Andy Hung224f82f2022-03-22 00:00:49 -070025#include <mediautils/MethodStatistics.h>
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080026#include <mediautils/TimeCheck.h>
27#include <utils/Log.h>
Eric Laurent42896a02019-09-27 15:40:33 -070028#include "debuggerd/handler.h"
Eric Laurent3528c932018-02-23 17:17:22 -080029
Andy Hung5c6d68a2022-03-09 21:54:59 -080030namespace android::mediautils {
Eric Laurent3528c932018-02-23 17:17:22 -080031
Andy Hunga2a1ac32022-03-18 16:12:11 -070032/**
33 * Returns the std::string "HH:MM:SS.MSc" from a system_clock time_point.
34 */
Ytai Ben-Tsvi34f26b12021-12-02 13:58:38 -080035std::string formatTime(std::chrono::system_clock::time_point t) {
Andy Hunga2a1ac32022-03-18 16:12:11 -070036 auto time_string = audio_utils_time_string_from_ns(
37 std::chrono::nanoseconds(t.time_since_epoch()).count());
38
39 // The time string is 19 characters (including null termination).
40 // Example: "03-27 16:47:06.187"
41 // MM DD HH MM SS MS
42 // We offset by 6 to get HH:MM:SS.MSc
43 //
44 return time_string.time + 6; // offset to remove month/day.
Ytai Ben-Tsvi34f26b12021-12-02 13:58:38 -080045}
46
Andy Hunga2a1ac32022-03-18 16:12:11 -070047/**
48 * Finds the end of the common time prefix.
49 *
50 * This is as an option to remove the common time prefix to avoid
51 * unnecessary duplicated strings.
52 *
53 * \param time1 a time string
54 * \param time2 a time string
55 * \return the position where the common time prefix ends. For abbreviated
56 * printing of time2, offset the character pointer by this position.
57 */
58static size_t commonTimePrefixPosition(std::string_view time1, std::string_view time2) {
59 const size_t endPos = std::min(time1.size(), time2.size());
60 size_t i;
61
62 // Find location of the first mismatch between strings
63 for (i = 0; ; ++i) {
64 if (i == endPos) {
65 return i; // strings match completely to the length of one of the strings.
66 }
67 if (time1[i] != time2[i]) {
68 break;
69 }
70 if (time1[i] == '\0') {
71 return i; // "printed" strings match completely. No need to check further.
72 }
73 }
74
75 // Go backwards until we find a delimeter or space.
76 for (; i > 0
77 && isdigit(time1[i]) // still a number
78 && time1[i - 1] != ' '
79 ; --i) {
80 }
81 return i;
82}
83
84/**
85 * Returns the unique suffix of time2 that isn't present in time1.
86 *
87 * If time2 is identical to time1, then an empty string_view is returned.
88 * This method is used to elide the common prefix when printing times.
89 */
90std::string_view timeSuffix(std::string_view time1, std::string_view time2) {
91 const size_t pos = commonTimePrefixPosition(time1, time2);
92 return time2.substr(pos);
93}
Ytai Ben-Tsvi34f26b12021-12-02 13:58:38 -080094
Eric Laurent42896a02019-09-27 15:40:33 -070095// Audio HAL server pids vector used to generate audio HAL processes tombstone
96// when audioserver watchdog triggers.
97// We use a lockless storage to avoid potential deadlocks in the context of watchdog
98// trigger.
99// Protection again simultaneous writes is not needed given one update takes place
100// during AudioFlinger construction and other comes necessarily later once the IAudioFlinger
101// interface is available.
102// The use of an atomic index just guaranties that current vector is fully initialized
103// when read.
104/* static */
105void TimeCheck::accessAudioHalPids(std::vector<pid_t>* pids, bool update) {
106 static constexpr int kNumAudioHalPidsVectors = 3;
107 static std::vector<pid_t> audioHalPids[kNumAudioHalPidsVectors];
Andy Hung5c6d68a2022-03-09 21:54:59 -0800108 static std::atomic<unsigned> curAudioHalPids = 0;
Eric Laurent42896a02019-09-27 15:40:33 -0700109
110 if (update) {
Eric Laurent1ad278b2021-03-05 18:09:01 +0100111 audioHalPids[(curAudioHalPids++ + 1) % kNumAudioHalPidsVectors] = *pids;
Eric Laurent42896a02019-09-27 15:40:33 -0700112 } else {
Eric Laurent1ad278b2021-03-05 18:09:01 +0100113 *pids = audioHalPids[curAudioHalPids % kNumAudioHalPidsVectors];
Eric Laurent42896a02019-09-27 15:40:33 -0700114 }
115}
116
117/* static */
118void TimeCheck::setAudioHalPids(const std::vector<pid_t>& pids) {
119 accessAudioHalPids(&(const_cast<std::vector<pid_t>&>(pids)), true);
120}
121
122/* static */
123std::vector<pid_t> TimeCheck::getAudioHalPids() {
124 std::vector<pid_t> pids;
125 accessAudioHalPids(&pids, false);
126 return pids;
127}
128
Eric Laurent3528c932018-02-23 17:17:22 -0800129/* static */
Andy Hung5c6d68a2022-03-09 21:54:59 -0800130TimerThread& TimeCheck::getTimeCheckThread() {
131 static TimerThread sTimeCheckThread{};
Eric Laurent3528c932018-02-23 17:17:22 -0800132 return sTimeCheckThread;
133}
134
Andy Hunga2a1ac32022-03-18 16:12:11 -0700135/* static */
136std::string TimeCheck::toString() {
137 // note pending and retired are individually locked for maximum concurrency,
138 // snapshot is not instantaneous at a single time.
139 return getTimeCheckThread().toString();
140}
141
Andy Hung35f96152022-07-15 15:18:59 -0700142TimeCheck::TimeCheck(std::string_view tag, OnTimerFunc&& onTimer, uint32_t timeoutMs,
Andy Hung5c6d68a2022-03-09 21:54:59 -0800143 bool crashOnTimeout)
Andy Hung35f96152022-07-15 15:18:59 -0700144 : mTimeCheckHandler{ std::make_shared<TimeCheckHandler>(
145 tag, std::move(onTimer), crashOnTimeout,
146 std::chrono::system_clock::now(), gettid()) }
Andy Hunga2a1ac32022-03-18 16:12:11 -0700147 , mTimerHandle(timeoutMs == 0
148 ? getTimeCheckThread().trackTask(mTimeCheckHandler->tag)
149 : getTimeCheckThread().scheduleTask(
150 mTimeCheckHandler->tag,
151 // Pass in all the arguments by value to this task for safety.
152 // The thread could call the callback before the constructor is finished.
153 // The destructor is not blocked on callback.
154 [ timeCheckHandler = mTimeCheckHandler ] {
155 timeCheckHandler->onTimeout();
156 },
157 std::chrono::milliseconds(timeoutMs))) {}
Eric Laurent3528c932018-02-23 17:17:22 -0800158
159TimeCheck::~TimeCheck() {
Andy Hunga2a1ac32022-03-18 16:12:11 -0700160 if (mTimeCheckHandler) {
161 mTimeCheckHandler->onCancel(mTimerHandle);
162 }
Eric Laurent3528c932018-02-23 17:17:22 -0800163}
164
Andy Hung5c6d68a2022-03-09 21:54:59 -0800165void TimeCheck::TimeCheckHandler::onCancel(TimerThread::Handle timerHandle) const
166{
167 if (TimeCheck::getTimeCheckThread().cancelTask(timerHandle) && onTimer) {
168 const std::chrono::system_clock::time_point endTime = std::chrono::system_clock::now();
169 onTimer(false /* timeout */,
170 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
171 endTime - startTime).count());
172 }
173}
174
175void TimeCheck::TimeCheckHandler::onTimeout() const
176{
177 const std::chrono::system_clock::time_point endTime = std::chrono::system_clock::now();
178 if (onTimer) {
179 onTimer(true /* timeout */,
180 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
181 endTime - startTime).count());
182 }
183
184 if (!crashOnTimeout) return;
Ytai Ben-Tsvi34f26b12021-12-02 13:58:38 -0800185
Andy Hunga2a1ac32022-03-18 16:12:11 -0700186 // Generate the TimerThread summary string early before sending signals to the
187 // HAL processes which can affect thread behavior.
188 const std::string summary = getTimeCheckThread().toString(4 /* retiredCount */);
189
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800190 // Generate audio HAL processes tombstones and allow time to complete
191 // before forcing restart
Andy Hung5c6d68a2022-03-09 21:54:59 -0800192 std::vector<pid_t> pids = TimeCheck::getAudioHalPids();
Jaideep Sharmaeaf9d9c2022-05-13 15:15:27 +0530193 std::string halPids = "HAL pids [ ";
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800194 if (pids.size() != 0) {
195 for (const auto& pid : pids) {
196 ALOGI("requesting tombstone for pid: %d", pid);
Jaideep Sharmaeaf9d9c2022-05-13 15:15:27 +0530197 halPids.append(std::to_string(pid)).append(" ");
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800198 sigqueue(pid, DEBUGGER_SIGNAL, {.sival_int = 0});
Eric Laurent3528c932018-02-23 17:17:22 -0800199 }
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800200 sleep(1);
201 } else {
202 ALOGI("No HAL process pid available, skipping tombstones");
Eric Laurent39b09b52018-06-29 12:24:40 -0700203 }
Jaideep Sharmaeaf9d9c2022-05-13 15:15:27 +0530204 halPids.append("]");
Andy Hungf45f34c2022-03-25 13:09:03 -0700205
Andy Hung5c6d68a2022-03-09 21:54:59 -0800206 LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag.c_str());
Andy Hung10ac7112022-03-28 08:00:40 -0700207
208 // Create abort message string - caution: this can be very large.
209 const std::string abortMessage = std::string("TimeCheck timeout for ")
210 .append(tag)
211 .append(" scheduled ").append(formatTime(startTime))
212 .append(" on thread ").append(std::to_string(tid)).append("\n")
Jaideep Sharmaeaf9d9c2022-05-13 15:15:27 +0530213 .append(halPids).append("\n")
Andy Hung10ac7112022-03-28 08:00:40 -0700214 .append(summary);
215
216 // Note: LOG_ALWAYS_FATAL limits the size of the string - per log/log.h:
217 // Log message text may be truncated to less than an
218 // implementation-specific limit (1023 bytes).
219 //
220 // Here, we send the string through android-base/logging.h LOG()
221 // to avoid the size limitation. LOG(FATAL) does an abort whereas
222 // LOG(FATAL_WITHOUT_ABORT) does not abort.
223
224 LOG(FATAL) << abortMessage;
Eric Laurent3528c932018-02-23 17:17:22 -0800225}
226
Andy Hung224f82f2022-03-22 00:00:49 -0700227// Automatically create a TimeCheck class for a class and method.
228// This is used for Audio HIDL support.
229mediautils::TimeCheck makeTimeCheckStatsForClassMethod(
230 std::string_view className, std::string_view methodName) {
231 std::shared_ptr<MethodStatistics<std::string>> statistics =
232 mediautils::getStatisticsForClass(className);
233 if (!statistics) return {}; // empty TimeCheck.
234 return mediautils::TimeCheck(
Andy Hung35f96152022-07-15 15:18:59 -0700235 FixedString62(className).append("::").append(methodName),
236 [ safeMethodName = FixedString30(methodName),
Andy Hung224f82f2022-03-22 00:00:49 -0700237 stats = std::move(statistics) ]
238 (bool timeout, float elapsedMs) {
239 if (timeout) {
240 ; // ignored, there is no timeout value.
241 } else {
Andy Hung35f96152022-07-15 15:18:59 -0700242 stats->event(safeMethodName.asStringView(), elapsedMs);
Andy Hung224f82f2022-03-22 00:00:49 -0700243 }
244 }, 0 /* timeoutMs */);
245}
246
Andy Hung5c6d68a2022-03-09 21:54:59 -0800247} // namespace android::mediautils