audio services: monitor execution time for binder commands

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: I01b5bf2599fb2a4cd265cbbe8d4e34b2b059aaf4
gugelfrei
Eric Laurent 6 years ago
parent 12cc6e7a41
commit 3528c9330f

@ -0,0 +1 @@
../../media/libmedia/include/media/TimeCheck.h

@ -24,6 +24,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <media/TimeCheck.h>
#include <private/android_filesystem_config.h>
#include "IAudioFlinger.h"
@ -933,6 +934,8 @@ status_t BnAudioFlinger::onTransact(
break;
}
TimeCheck check("IAudioFlinger");
switch (code) {
case CREATE_TRACK: {
CHECK_INTERFACE(IAudioFlinger, data, reply);

@ -27,6 +27,7 @@
#include <media/AudioEffect.h>
#include <media/IAudioPolicyService.h>
#include <media/TimeCheck.h>
#include <private/android_filesystem_config.h>
#include <system/audio.h>
@ -882,6 +883,8 @@ status_t BnAudioPolicyService::onTransact(
break;
}
TimeCheck check("IAudioPolicyService");
switch (code) {
case SET_DEVICE_CONNECTION_STATE: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);

@ -18,7 +18,7 @@ cc_library {
vndk: {
enabled: true,
},
srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
srcs: ["AudioParameter.cpp", "TypeConverter.cpp", "TimeCheck.cpp"],
cflags: [
"-Werror",
"-Wno-error=deprecated-declarations",

@ -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…
Cancel
Save