Add a mechanism to monitor execution time of incoming binder calls to audio flinger and audio policy and cause native audioserver restart in case of timeout. Bug: 69250055 Test: manual. audio smoke tests Change-Id: I01b5bf2599fb2a4cd265cbbe8d4e34b2b059aaf4gugelfrei
parent
12cc6e7a41
commit
3528c9330f
@ -0,0 +1 @@
|
||||
../../media/libmedia/include/media/TimeCheck.h
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include <media/TimeCheck.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/* 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;
|
||||
const char *tag;
|
||||
{
|
||||
AutoMutex _l(mMutex);
|
||||
|
||||
if (exitPending()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsecs_t endTimeNs = INT64_MAX;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "TimeCheck timeout for %s", tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // namespace android
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ANDROID_TIME_CHECK_H
|
||||
#define ANDROID_TIME_CHECK_H
|
||||
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/Thread.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// A class monitoring execution time for a code block (scoped variable) and causing an assert
|
||||
// if it exceeds a certain time
|
||||
|
||||
class TimeCheck {
|
||||
public:
|
||||
|
||||
// The default timeout is chosen to be less than system server watchdog timeout
|
||||
static constexpr uint32_t kDefaultTimeOutMs = 5000;
|
||||
|
||||
TimeCheck(const char *tag, uint32_t timeoutMs = kDefaultTimeOutMs);
|
||||
~TimeCheck();
|
||||
|
||||
private:
|
||||
|
||||
class TimeCheckThread : public Thread {
|
||||
public:
|
||||
|
||||
TimeCheckThread() {}
|
||||
virtual ~TimeCheckThread() override;
|
||||
|
||||
nsecs_t startMonitoring(const char *tag, uint32_t timeoutMs);
|
||||
void stopMonitoring(nsecs_t endTimeNs);
|
||||
|
||||
private:
|
||||
|
||||
// RefBase
|
||||
virtual void onFirstRef() override { run("TimeCheckThread", PRIORITY_URGENT_AUDIO); }
|
||||
|
||||
// Thread
|
||||
virtual bool threadLoop() override;
|
||||
|
||||
Condition mCond;
|
||||
Mutex mMutex;
|
||||
// using the end time in ns as key is OK given the risk is low that two entries
|
||||
// are added in such a way that <add time> + <timeout> are the same for both.
|
||||
KeyedVector< nsecs_t, const char*> mMonitorRequests;
|
||||
};
|
||||
|
||||
static sp<TimeCheckThread> getTimeCheckThread();
|
||||
|
||||
const nsecs_t mEndTimeNs;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_TIME_CHECK_H
|
Loading…
Reference in new issue