blob: 023797707084e4f8babebf1c129c96612582ddfa [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 Hunga2a1ac32022-03-18 16:12:11 -070021#include <audio_utils/clock.h>
Marco Nelissencf90b492019-09-26 11:20:54 -070022#include <mediautils/EventLog.h>
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080023#include <mediautils/TimeCheck.h>
24#include <utils/Log.h>
Eric Laurent42896a02019-09-27 15:40:33 -070025#include "debuggerd/handler.h"
Eric Laurent3528c932018-02-23 17:17:22 -080026
Andy Hung5c6d68a2022-03-09 21:54:59 -080027namespace android::mediautils {
Eric Laurent3528c932018-02-23 17:17:22 -080028
Andy Hunga2a1ac32022-03-18 16:12:11 -070029/**
30 * Returns the std::string "HH:MM:SS.MSc" from a system_clock time_point.
31 */
Ytai Ben-Tsvi34f26b12021-12-02 13:58:38 -080032std::string formatTime(std::chrono::system_clock::time_point t) {
Andy Hunga2a1ac32022-03-18 16:12:11 -070033 auto time_string = audio_utils_time_string_from_ns(
34 std::chrono::nanoseconds(t.time_since_epoch()).count());
35
36 // The time string is 19 characters (including null termination).
37 // Example: "03-27 16:47:06.187"
38 // MM DD HH MM SS MS
39 // We offset by 6 to get HH:MM:SS.MSc
40 //
41 return time_string.time + 6; // offset to remove month/day.
Ytai Ben-Tsvi34f26b12021-12-02 13:58:38 -080042}
43
Andy Hunga2a1ac32022-03-18 16:12:11 -070044/**
45 * Finds the end of the common time prefix.
46 *
47 * This is as an option to remove the common time prefix to avoid
48 * unnecessary duplicated strings.
49 *
50 * \param time1 a time string
51 * \param time2 a time string
52 * \return the position where the common time prefix ends. For abbreviated
53 * printing of time2, offset the character pointer by this position.
54 */
55static size_t commonTimePrefixPosition(std::string_view time1, std::string_view time2) {
56 const size_t endPos = std::min(time1.size(), time2.size());
57 size_t i;
58
59 // Find location of the first mismatch between strings
60 for (i = 0; ; ++i) {
61 if (i == endPos) {
62 return i; // strings match completely to the length of one of the strings.
63 }
64 if (time1[i] != time2[i]) {
65 break;
66 }
67 if (time1[i] == '\0') {
68 return i; // "printed" strings match completely. No need to check further.
69 }
70 }
71
72 // Go backwards until we find a delimeter or space.
73 for (; i > 0
74 && isdigit(time1[i]) // still a number
75 && time1[i - 1] != ' '
76 ; --i) {
77 }
78 return i;
79}
80
81/**
82 * Returns the unique suffix of time2 that isn't present in time1.
83 *
84 * If time2 is identical to time1, then an empty string_view is returned.
85 * This method is used to elide the common prefix when printing times.
86 */
87std::string_view timeSuffix(std::string_view time1, std::string_view time2) {
88 const size_t pos = commonTimePrefixPosition(time1, time2);
89 return time2.substr(pos);
90}
Ytai Ben-Tsvi34f26b12021-12-02 13:58:38 -080091
Eric Laurent42896a02019-09-27 15:40:33 -070092// Audio HAL server pids vector used to generate audio HAL processes tombstone
93// when audioserver watchdog triggers.
94// We use a lockless storage to avoid potential deadlocks in the context of watchdog
95// trigger.
96// Protection again simultaneous writes is not needed given one update takes place
97// during AudioFlinger construction and other comes necessarily later once the IAudioFlinger
98// interface is available.
99// The use of an atomic index just guaranties that current vector is fully initialized
100// when read.
101/* static */
102void TimeCheck::accessAudioHalPids(std::vector<pid_t>* pids, bool update) {
103 static constexpr int kNumAudioHalPidsVectors = 3;
104 static std::vector<pid_t> audioHalPids[kNumAudioHalPidsVectors];
Andy Hung5c6d68a2022-03-09 21:54:59 -0800105 static std::atomic<unsigned> curAudioHalPids = 0;
Eric Laurent42896a02019-09-27 15:40:33 -0700106
107 if (update) {
Eric Laurent1ad278b2021-03-05 18:09:01 +0100108 audioHalPids[(curAudioHalPids++ + 1) % kNumAudioHalPidsVectors] = *pids;
Eric Laurent42896a02019-09-27 15:40:33 -0700109 } else {
Eric Laurent1ad278b2021-03-05 18:09:01 +0100110 *pids = audioHalPids[curAudioHalPids % kNumAudioHalPidsVectors];
Eric Laurent42896a02019-09-27 15:40:33 -0700111 }
112}
113
114/* static */
115void TimeCheck::setAudioHalPids(const std::vector<pid_t>& pids) {
116 accessAudioHalPids(&(const_cast<std::vector<pid_t>&>(pids)), true);
117}
118
119/* static */
120std::vector<pid_t> TimeCheck::getAudioHalPids() {
121 std::vector<pid_t> pids;
122 accessAudioHalPids(&pids, false);
123 return pids;
124}
125
Eric Laurent3528c932018-02-23 17:17:22 -0800126/* static */
Andy Hung5c6d68a2022-03-09 21:54:59 -0800127TimerThread& TimeCheck::getTimeCheckThread() {
128 static TimerThread sTimeCheckThread{};
Eric Laurent3528c932018-02-23 17:17:22 -0800129 return sTimeCheckThread;
130}
131
Andy Hunga2a1ac32022-03-18 16:12:11 -0700132/* static */
133std::string TimeCheck::toString() {
134 // note pending and retired are individually locked for maximum concurrency,
135 // snapshot is not instantaneous at a single time.
136 return getTimeCheckThread().toString();
137}
138
Andy Hung5c6d68a2022-03-09 21:54:59 -0800139TimeCheck::TimeCheck(std::string tag, OnTimerFunc&& onTimer, uint32_t timeoutMs,
140 bool crashOnTimeout)
141 : mTimeCheckHandler(new TimeCheckHandler{
142 std::move(tag), std::move(onTimer), crashOnTimeout,
143 std::chrono::system_clock::now(), gettid()})
Andy Hunga2a1ac32022-03-18 16:12:11 -0700144 , mTimerHandle(timeoutMs == 0
145 ? getTimeCheckThread().trackTask(mTimeCheckHandler->tag)
146 : getTimeCheckThread().scheduleTask(
147 mTimeCheckHandler->tag,
148 // Pass in all the arguments by value to this task for safety.
149 // The thread could call the callback before the constructor is finished.
150 // The destructor is not blocked on callback.
151 [ timeCheckHandler = mTimeCheckHandler ] {
152 timeCheckHandler->onTimeout();
153 },
154 std::chrono::milliseconds(timeoutMs))) {}
Eric Laurent3528c932018-02-23 17:17:22 -0800155
156TimeCheck::~TimeCheck() {
Andy Hunga2a1ac32022-03-18 16:12:11 -0700157 if (mTimeCheckHandler) {
158 mTimeCheckHandler->onCancel(mTimerHandle);
159 }
Eric Laurent3528c932018-02-23 17:17:22 -0800160}
161
Andy Hung5c6d68a2022-03-09 21:54:59 -0800162void TimeCheck::TimeCheckHandler::onCancel(TimerThread::Handle timerHandle) const
163{
164 if (TimeCheck::getTimeCheckThread().cancelTask(timerHandle) && onTimer) {
165 const std::chrono::system_clock::time_point endTime = std::chrono::system_clock::now();
166 onTimer(false /* timeout */,
167 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
168 endTime - startTime).count());
169 }
170}
171
172void TimeCheck::TimeCheckHandler::onTimeout() const
173{
174 const std::chrono::system_clock::time_point endTime = std::chrono::system_clock::now();
175 if (onTimer) {
176 onTimer(true /* timeout */,
177 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
178 endTime - startTime).count());
179 }
180
181 if (!crashOnTimeout) return;
Ytai Ben-Tsvi34f26b12021-12-02 13:58:38 -0800182
Andy Hunga2a1ac32022-03-18 16:12:11 -0700183 // Generate the TimerThread summary string early before sending signals to the
184 // HAL processes which can affect thread behavior.
185 const std::string summary = getTimeCheckThread().toString(4 /* retiredCount */);
186
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800187 // Generate audio HAL processes tombstones and allow time to complete
188 // before forcing restart
Andy Hung5c6d68a2022-03-09 21:54:59 -0800189 std::vector<pid_t> pids = TimeCheck::getAudioHalPids();
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800190 if (pids.size() != 0) {
191 for (const auto& pid : pids) {
192 ALOGI("requesting tombstone for pid: %d", pid);
193 sigqueue(pid, DEBUGGER_SIGNAL, {.sival_int = 0});
Eric Laurent3528c932018-02-23 17:17:22 -0800194 }
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800195 sleep(1);
196 } else {
197 ALOGI("No HAL process pid available, skipping tombstones");
Eric Laurent39b09b52018-06-29 12:24:40 -0700198 }
Andy Hung5c6d68a2022-03-09 21:54:59 -0800199 LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag.c_str());
Andy Hunga2a1ac32022-03-18 16:12:11 -0700200 LOG_ALWAYS_FATAL("TimeCheck timeout for %s scheduled %s on thread %d\n%s",
201 tag.c_str(), formatTime(startTime).c_str(), tid, summary.c_str());
Eric Laurent3528c932018-02-23 17:17:22 -0800202}
203
Andy Hung5c6d68a2022-03-09 21:54:59 -0800204} // namespace android::mediautils