1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "TimeCheck"
#include <utils/Log.h>
#include <mediautils/TimeCheck.h>
#include <mediautils/EventLog.h>
#include "debuggerd/handler.h"
namespace android {
// Audio HAL server pids vector used to generate audio HAL processes tombstone
// when audioserver watchdog triggers.
// We use a lockless storage to avoid potential deadlocks in the context of watchdog
// trigger.
// Protection again simultaneous writes is not needed given one update takes place
// during AudioFlinger construction and other comes necessarily later once the IAudioFlinger
// interface is available.
// The use of an atomic index just guaranties that current vector is fully initialized
// when read.
/* static */
void TimeCheck::accessAudioHalPids(std::vector<pid_t>* pids, bool update) {
static constexpr int kNumAudioHalPidsVectors = 3;
static std::vector<pid_t> audioHalPids[kNumAudioHalPidsVectors];
static std::atomic<int> curAudioHalPids = 0;
if (update) {
audioHalPids[(curAudioHalPids++ + 1) % kNumAudioHalPidsVectors] = *pids;
} else {
*pids = audioHalPids[curAudioHalPids % kNumAudioHalPidsVectors];
}
}
/* static */
void TimeCheck::setAudioHalPids(const std::vector<pid_t>& pids) {
accessAudioHalPids(&(const_cast<std::vector<pid_t>&>(pids)), true);
}
/* static */
std::vector<pid_t> TimeCheck::getAudioHalPids() {
std::vector<pid_t> pids;
accessAudioHalPids(&pids, false);
return pids;
}
/* static */
sp<TimeCheck::TimeCheckThread> TimeCheck::getTimeCheckThread()
{
static sp<TimeCheck::TimeCheckThread> sTimeCheckThread = new TimeCheck::TimeCheckThread();
return sTimeCheckThread;
}
TimeCheck::TimeCheck(const char *tag, uint32_t timeoutMs)
: mEndTimeNs(getTimeCheckThread()->startMonitoring(tag, timeoutMs))
{
}
TimeCheck::~TimeCheck() {
getTimeCheckThread()->stopMonitoring(mEndTimeNs);
}
TimeCheck::TimeCheckThread::~TimeCheckThread()
{
AutoMutex _l(mMutex);
requestExit();
mMonitorRequests.clear();
mCond.signal();
}
nsecs_t TimeCheck::TimeCheckThread::startMonitoring(const char *tag, uint32_t timeoutMs) {
Mutex::Autolock _l(mMutex);
nsecs_t endTimeNs = systemTime() + milliseconds(timeoutMs);
for (; mMonitorRequests.indexOfKey(endTimeNs) >= 0; ++endTimeNs);
mMonitorRequests.add(endTimeNs, tag);
mCond.signal();
return endTimeNs;
}
void TimeCheck::TimeCheckThread::stopMonitoring(nsecs_t endTimeNs) {
Mutex::Autolock _l(mMutex);
mMonitorRequests.removeItem(endTimeNs);
mCond.signal();
}
bool TimeCheck::TimeCheckThread::threadLoop()
{
status_t status = TIMED_OUT;
{
AutoMutex _l(mMutex);
if (exitPending()) {
return false;
}
nsecs_t endTimeNs = INT64_MAX;
const char *tag = "<unspecified>";
// KeyedVector mMonitorRequests is ordered so take first entry as next timeout
if (mMonitorRequests.size() != 0) {
endTimeNs = mMonitorRequests.keyAt(0);
tag = mMonitorRequests.valueAt(0);
}
const nsecs_t waitTimeNs = endTimeNs - systemTime();
if (waitTimeNs > 0) {
status = mCond.waitRelative(mMutex, waitTimeNs);
}
if (status != NO_ERROR) {
// Generate audio HAL processes tombstones and allow time to complete
// before forcing restart
std::vector<pid_t> pids = getAudioHalPids();
if (pids.size() != 0) {
for (const auto& pid : pids) {
ALOGI("requesting tombstone for pid: %d", pid);
sigqueue(pid, DEBUGGER_SIGNAL, {.sival_int = 0});
}
sleep(1);
} else {
ALOGI("No HAL process pid available, skipping tombstones");
}
LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag);
LOG_ALWAYS_FATAL("TimeCheck timeout for %s", tag);
}
}
return true;
}
}; // namespace android
|