| Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 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 |  | 
| Eric Laurent | 42896a0 | 2019-09-27 15:40:33 -0700 | [diff] [blame] | 17 | #define LOG_TAG "TimeCheck" | 
| Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 18 |  | 
| Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 19 | #include <optional> | 
|  | 20 |  | 
| Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 21 | #include <audio_utils/clock.h> | 
| Marco Nelissen | cf90b49 | 2019-09-26 11:20:54 -0700 | [diff] [blame] | 22 | #include <mediautils/EventLog.h> | 
| Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 23 | #include <mediautils/TimeCheck.h> | 
|  | 24 | #include <utils/Log.h> | 
| Eric Laurent | 42896a0 | 2019-09-27 15:40:33 -0700 | [diff] [blame] | 25 | #include "debuggerd/handler.h" | 
| Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 26 |  | 
| Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 27 | namespace android::mediautils { | 
| Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 28 |  | 
| Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 29 | /** | 
|  | 30 | * Returns the std::string "HH:MM:SS.MSc" from a system_clock time_point. | 
|  | 31 | */ | 
| Ytai Ben-Tsvi | 34f26b1 | 2021-12-02 13:58:38 -0800 | [diff] [blame] | 32 | std::string formatTime(std::chrono::system_clock::time_point t) { | 
| Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 33 | 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-Tsvi | 34f26b1 | 2021-12-02 13:58:38 -0800 | [diff] [blame] | 42 | } | 
|  | 43 |  | 
| Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 44 | /** | 
|  | 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 | */ | 
|  | 55 | static 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 | */ | 
|  | 87 | std::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-Tsvi | 34f26b1 | 2021-12-02 13:58:38 -0800 | [diff] [blame] | 91 |  | 
| Eric Laurent | 42896a0 | 2019-09-27 15:40:33 -0700 | [diff] [blame] | 92 | // 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 */ | 
|  | 102 | void TimeCheck::accessAudioHalPids(std::vector<pid_t>* pids, bool update) { | 
|  | 103 | static constexpr int kNumAudioHalPidsVectors = 3; | 
|  | 104 | static std::vector<pid_t> audioHalPids[kNumAudioHalPidsVectors]; | 
| Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 105 | static std::atomic<unsigned> curAudioHalPids = 0; | 
| Eric Laurent | 42896a0 | 2019-09-27 15:40:33 -0700 | [diff] [blame] | 106 |  | 
|  | 107 | if (update) { | 
| Eric Laurent | 1ad278b | 2021-03-05 18:09:01 +0100 | [diff] [blame] | 108 | audioHalPids[(curAudioHalPids++ + 1) % kNumAudioHalPidsVectors] = *pids; | 
| Eric Laurent | 42896a0 | 2019-09-27 15:40:33 -0700 | [diff] [blame] | 109 | } else { | 
| Eric Laurent | 1ad278b | 2021-03-05 18:09:01 +0100 | [diff] [blame] | 110 | *pids = audioHalPids[curAudioHalPids % kNumAudioHalPidsVectors]; | 
| Eric Laurent | 42896a0 | 2019-09-27 15:40:33 -0700 | [diff] [blame] | 111 | } | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | /* static */ | 
|  | 115 | void TimeCheck::setAudioHalPids(const std::vector<pid_t>& pids) { | 
|  | 116 | accessAudioHalPids(&(const_cast<std::vector<pid_t>&>(pids)), true); | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | /* static */ | 
|  | 120 | std::vector<pid_t> TimeCheck::getAudioHalPids() { | 
|  | 121 | std::vector<pid_t> pids; | 
|  | 122 | accessAudioHalPids(&pids, false); | 
|  | 123 | return pids; | 
|  | 124 | } | 
|  | 125 |  | 
| Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 126 | /* static */ | 
| Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 127 | TimerThread& TimeCheck::getTimeCheckThread() { | 
|  | 128 | static TimerThread sTimeCheckThread{}; | 
| Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 129 | return sTimeCheckThread; | 
|  | 130 | } | 
|  | 131 |  | 
| Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 132 | /* static */ | 
|  | 133 | std::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 Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 139 | TimeCheck::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 Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 144 | , 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 Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 155 |  | 
|  | 156 | TimeCheck::~TimeCheck() { | 
| Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 157 | if (mTimeCheckHandler) { | 
|  | 158 | mTimeCheckHandler->onCancel(mTimerHandle); | 
|  | 159 | } | 
| Eric Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 160 | } | 
|  | 161 |  | 
| Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 162 | void 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 |  | 
|  | 172 | void 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-Tsvi | 34f26b1 | 2021-12-02 13:58:38 -0800 | [diff] [blame] | 182 |  | 
| Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 183 | // 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-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 187 | // Generate audio HAL processes tombstones and allow time to complete | 
|  | 188 | // before forcing restart | 
| Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 189 | std::vector<pid_t> pids = TimeCheck::getAudioHalPids(); | 
| Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 190 | 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 Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 194 | } | 
| Ytai Ben-Tsvi | 1ea62c9 | 2021-11-10 14:38:27 -0800 | [diff] [blame] | 195 | sleep(1); | 
|  | 196 | } else { | 
|  | 197 | ALOGI("No HAL process pid available, skipping tombstones"); | 
| Eric Laurent | 39b09b5 | 2018-06-29 12:24:40 -0700 | [diff] [blame] | 198 | } | 
| Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 199 | LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag.c_str()); | 
| Andy Hung | a2a1ac3 | 2022-03-18 16:12:11 -0700 | [diff] [blame^] | 200 | 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 Laurent | 3528c93 | 2018-02-23 17:17:22 -0800 | [diff] [blame] | 202 | } | 
|  | 203 |  | 
| Andy Hung | 5c6d68a | 2022-03-09 21:54:59 -0800 | [diff] [blame] | 204 | }  // namespace android::mediautils |