diff --git a/include/media/TimeCheck.h b/include/media/TimeCheck.h new file mode 120000 index 0000000000..e3ef134404 --- /dev/null +++ b/include/media/TimeCheck.h @@ -0,0 +1 @@ +../../media/libmedia/include/media/TimeCheck.h \ No newline at end of file diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp index 3358e35fda..873d836519 100644 --- a/media/libaudioclient/IAudioFlinger.cpp +++ b/media/libaudioclient/IAudioFlinger.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #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); diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp index 8f5ff30ac4..0b98502af8 100644 --- a/media/libaudioclient/IAudioPolicyService.cpp +++ b/media/libaudioclient/IAudioPolicyService.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -882,6 +883,8 @@ status_t BnAudioPolicyService::onTransact( break; } + TimeCheck check("IAudioPolicyService"); + switch (code) { case SET_DEVICE_CONNECTION_STATE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp index 34b15a85c0..3990e697f9 100644 --- a/media/libmedia/Android.bp +++ b/media/libmedia/Android.bp @@ -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", diff --git a/media/libmedia/TimeCheck.cpp b/media/libmedia/TimeCheck.cpp new file mode 100644 index 0000000000..dab5d4f336 --- /dev/null +++ b/media/libmedia/TimeCheck.cpp @@ -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 + +namespace android { + +/* static */ +sp TimeCheck::getTimeCheckThread() +{ + static sp 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 diff --git a/media/libmedia/include/media/TimeCheck.h b/media/libmedia/include/media/TimeCheck.h new file mode 100644 index 0000000000..6c5f656ebc --- /dev/null +++ b/media/libmedia/include/media/TimeCheck.h @@ -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 +#include + + +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 + are the same for both. + KeyedVector< nsecs_t, const char*> mMonitorRequests; + }; + + static sp getTimeCheckThread(); + + const nsecs_t mEndTimeNs; +}; + +}; // namespace android + +#endif // ANDROID_TIME_CHECK_H