summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/TimedEventQueue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/TimedEventQueue.cpp')
-rw-r--r--media/libstagefright/TimedEventQueue.cpp103
1 files changed, 97 insertions, 6 deletions
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 7e9c4bf..0afac69 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -31,17 +31,29 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
+#include <binder/IServiceManager.h>
+#include <powermanager/PowerManager.h>
+#include <binder/IPCThreadState.h>
+#include <utils/CallStack.h>
namespace android {
+static int64_t kWakelockMinDelay = 100000ll; // 100ms
+
TimedEventQueue::TimedEventQueue()
: mNextEventID(1),
mRunning(false),
- mStopped(false) {
+ mStopped(false),
+ mDeathRecipient(new PMDeathRecipient(this)),
+ mWakeLockCount(0) {
}
TimedEventQueue::~TimedEventQueue() {
stop();
+ if (mPowerManager != 0) {
+ sp<IBinder> binder = mPowerManager->asBinder();
+ binder->unlinkToDeath(mDeathRecipient);
+ }
}
void TimedEventQueue::start() {
@@ -76,6 +88,9 @@ void TimedEventQueue::stop(bool flush) {
void *dummy;
pthread_join(mThread, &dummy);
+ // some events may be left in the queue if we did not flush and the wake lock
+ // must be released.
+ releaseWakeLock_l(true /*force*/);
mQueue.clear();
mRunning = false;
@@ -112,11 +127,16 @@ TimedEventQueue::event_id TimedEventQueue::postTimedEvent(
QueueItem item;
item.event = event;
item.realtime_us = realtime_us;
+ item.has_wakelock = false;
if (it == mQueue.begin()) {
mQueueHeadChangedCondition.signal();
}
+ if (realtime_us > ALooper::GetNowUs() + kWakelockMinDelay) {
+ acquireWakeLock_l();
+ item.has_wakelock = true;
+ }
mQueue.insert(it, item);
mQueueNotEmptyCondition.signal();
@@ -171,8 +191,10 @@ void TimedEventQueue::cancelEvents(
ALOGV("cancelling event %d", (*it).event->eventID());
(*it).event->setEventID(0);
+ if ((*it).has_wakelock) {
+ releaseWakeLock_l();
+ }
it = mQueue.erase(it);
-
if (stopAfterFirstMatch) {
return;
}
@@ -195,6 +217,7 @@ void TimedEventQueue::threadEntry() {
for (;;) {
int64_t now_us = 0;
sp<Event> event;
+ bool wakeLocked = false;
{
Mutex::Autolock autoLock(mLock);
@@ -261,26 +284,29 @@ void TimedEventQueue::threadEntry() {
// removeEventFromQueue_l will return NULL.
// Otherwise, the QueueItem will be removed
// from the queue and the referenced event returned.
- event = removeEventFromQueue_l(eventID);
+ event = removeEventFromQueue_l(eventID, &wakeLocked);
}
if (event != NULL) {
// Fire event with the lock NOT held.
event->fire(this, now_us);
+ if (wakeLocked) {
+ Mutex::Autolock autoLock(mLock);
+ releaseWakeLock_l();
+ }
}
}
}
sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l(
- event_id id) {
+ event_id id, bool *wakeLocked) {
for (List<QueueItem>::iterator it = mQueue.begin();
it != mQueue.end(); ++it) {
if ((*it).event->eventID() == id) {
sp<Event> event = (*it).event;
event->setEventID(0);
-
+ *wakeLocked = (*it).has_wakelock;
mQueue.erase(it);
-
return event;
}
}
@@ -290,5 +316,70 @@ sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l(
return NULL;
}
+void TimedEventQueue::acquireWakeLock_l()
+{
+ if (mWakeLockCount == 0) {
+ CHECK(mWakeLockToken == 0);
+ if (mPowerManager == 0) {
+ // use checkService() to avoid blocking if power service is not up yet
+ sp<IBinder> binder =
+ defaultServiceManager()->checkService(String16("power"));
+ if (binder == 0) {
+ ALOGW("cannot connect to the power manager service");
+ } else {
+ mPowerManager = interface_cast<IPowerManager>(binder);
+ binder->linkToDeath(mDeathRecipient);
+ }
+ }
+ if (mPowerManager != 0) {
+ sp<IBinder> binder = new BBinder();
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
+ binder,
+ String16("TimedEventQueue"),
+ String16("media"));
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ if (status == NO_ERROR) {
+ mWakeLockToken = binder;
+ mWakeLockCount++;
+ }
+ }
+ } else {
+ mWakeLockCount++;
+ }
+}
+
+void TimedEventQueue::releaseWakeLock_l(bool force)
+{
+ if (mWakeLockCount == 0) {
+ return;
+ }
+ if (force) {
+ // Force wakelock release below by setting reference count to 1.
+ mWakeLockCount = 1;
+ }
+ if (--mWakeLockCount == 0) {
+ CHECK(mWakeLockToken != 0);
+ if (mPowerManager != 0) {
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ mPowerManager->releaseWakeLock(mWakeLockToken, 0);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ }
+ mWakeLockToken.clear();
+ }
+}
+
+void TimedEventQueue::clearPowerManager()
+{
+ Mutex::Autolock _l(mLock);
+ releaseWakeLock_l(true /*force*/);
+ mPowerManager.clear();
+}
+
+void TimedEventQueue::PMDeathRecipient::binderDied(const wp<IBinder>& who)
+{
+ mQueue->clearPowerManager();
+}
+
} // namespace android