1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #undef __STRICT_ANSI__ 18 #define __STDINT_LIMITS 19 #define __STDC_LIMIT_MACROS 20 #include <stdint.h> 21 22 //#define LOG_NDEBUG 0 23 #define LOG_TAG "TimedEventQueue" 24 #include <utils/Log.h> 25 #include <utils/threads.h> 26 27 #include "include/TimedEventQueue.h" 28 29 #include <sys/prctl.h> 30 #include <sys/time.h> 31 32 #include <media/stagefright/foundation/ADebug.h> 33 #include <media/stagefright/foundation/ALooper.h> 34 #include <binder/IServiceManager.h> 35 #include <powermanager/PowerManager.h> 36 #include <binder/IPCThreadState.h> 37 #include <utils/CallStack.h> 38 39 namespace android { 40 41 static int64_t kWakelockMinDelay = 100000ll; // 100ms 42 43 TimedEventQueue::TimedEventQueue() 44 : mNextEventID(1), 45 mRunning(false), 46 mStopped(false), 47 mDeathRecipient(new PMDeathRecipient(this)), 48 mWakeLockCount(0) { 49 } 50 51 TimedEventQueue::~TimedEventQueue() { 52 stop(); 53 if (mPowerManager != 0) { 54 sp<IBinder> binder = mPowerManager->asBinder(); 55 binder->unlinkToDeath(mDeathRecipient); 56 } 57 } 58 59 void TimedEventQueue::start() { 60 if (mRunning) { 61 return; 62 } 63 64 mStopped = false; 65 66 pthread_attr_t attr; 67 pthread_attr_init(&attr); 68 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 69 70 pthread_create(&mThread, &attr, ThreadWrapper, this); 71 72 pthread_attr_destroy(&attr); 73 74 mRunning = true; 75 } 76 77 void TimedEventQueue::stop(bool flush) { 78 if (!mRunning) { 79 return; 80 } 81 82 if (flush) { 83 postEventToBack(new StopEvent); 84 } else { 85 postTimedEvent(new StopEvent, INT64_MIN); 86 } 87 88 void *dummy; 89 pthread_join(mThread, &dummy); 90 91 // some events may be left in the queue if we did not flush and the wake lock 92 // must be released. 93 releaseWakeLock_l(true /*force*/); 94 mQueue.clear(); 95 96 mRunning = false; 97 } 98 99 TimedEventQueue::event_id TimedEventQueue::postEvent(const sp<Event> &event) { 100 // Reserve an earlier timeslot an INT64_MIN to be able to post 101 // the StopEvent to the absolute head of the queue. 102 return postTimedEvent(event, INT64_MIN + 1); 103 } 104 105 TimedEventQueue::event_id TimedEventQueue::postEventToBack( 106 const sp<Event> &event) { 107 return postTimedEvent(event, INT64_MAX); 108 } 109 110 TimedEventQueue::event_id TimedEventQueue::postEventWithDelay( 111 const sp<Event> &event, int64_t delay_us) { 112 CHECK(delay_us >= 0); 113 return postTimedEvent(event, ALooper::GetNowUs() + delay_us); 114 } 115 116 TimedEventQueue::event_id TimedEventQueue::postTimedEvent( 117 const sp<Event> &event, int64_t realtime_us) { 118 Mutex::Autolock autoLock(mLock); 119 120 event->setEventID(mNextEventID++); 121 122 List<QueueItem>::iterator it = mQueue.begin(); 123 while (it != mQueue.end() && realtime_us >= (*it).realtime_us) { 124 ++it; 125 } 126 127 QueueItem item; 128 item.event = event; 129 item.realtime_us = realtime_us; 130 item.has_wakelock = false; 131 132 if (it == mQueue.begin()) { 133 mQueueHeadChangedCondition.signal(); 134 } 135 136 if (realtime_us > ALooper::GetNowUs() + kWakelockMinDelay) { 137 acquireWakeLock_l(); 138 item.has_wakelock = true; 139 } 140 mQueue.insert(it, item); 141 142 mQueueNotEmptyCondition.signal(); 143 144 return event->eventID(); 145 } 146 147 static bool MatchesEventID( 148 void *cookie, const sp<TimedEventQueue::Event> &event) { 149 TimedEventQueue::event_id *id = 150 static_cast<TimedEventQueue::event_id *>(cookie); 151 152 if (event->eventID() != *id) { 153 return false; 154 } 155 156 *id = 0; 157 158 return true; 159 } 160 161 bool TimedEventQueue::cancelEvent(event_id id) { 162 if (id == 0) { 163 return false; 164 } 165 166 cancelEvents(&MatchesEventID, &id, true /* stopAfterFirstMatch */); 167 168 // if MatchesEventID found a match, it will have set id to 0 169 // (which is not a valid event_id). 170 171 return id == 0; 172 } 173 174 void TimedEventQueue::cancelEvents( 175 bool (*predicate)(void *cookie, const sp<Event> &event), 176 void *cookie, 177 bool stopAfterFirstMatch) { 178 Mutex::Autolock autoLock(mLock); 179 180 List<QueueItem>::iterator it = mQueue.begin(); 181 while (it != mQueue.end()) { 182 if (!(*predicate)(cookie, (*it).event)) { 183 ++it; 184 continue; 185 } 186 187 if (it == mQueue.begin()) { 188 mQueueHeadChangedCondition.signal(); 189 } 190 191 ALOGV("cancelling event %d", (*it).event->eventID()); 192 193 (*it).event->setEventID(0); 194 if ((*it).has_wakelock) { 195 releaseWakeLock_l(); 196 } 197 it = mQueue.erase(it); 198 if (stopAfterFirstMatch) { 199 return; 200 } 201 } 202 } 203 204 // static 205 void *TimedEventQueue::ThreadWrapper(void *me) { 206 207 androidSetThreadPriority(0, ANDROID_PRIORITY_FOREGROUND); 208 209 static_cast<TimedEventQueue *>(me)->threadEntry(); 210 211 return NULL; 212 } 213 214 void TimedEventQueue::threadEntry() { 215 prctl(PR_SET_NAME, (unsigned long)"TimedEventQueue", 0, 0, 0); 216 217 for (;;) { 218 int64_t now_us = 0; 219 sp<Event> event; 220 bool wakeLocked = false; 221 222 { 223 Mutex::Autolock autoLock(mLock); 224 225 if (mStopped) { 226 break; 227 } 228 229 while (mQueue.empty()) { 230 mQueueNotEmptyCondition.wait(mLock); 231 } 232 233 event_id eventID = 0; 234 for (;;) { 235 if (mQueue.empty()) { 236 // The only event in the queue could have been cancelled 237 // while we were waiting for its scheduled time. 238 break; 239 } 240 241 List<QueueItem>::iterator it = mQueue.begin(); 242 eventID = (*it).event->eventID(); 243 244 now_us = ALooper::GetNowUs(); 245 int64_t when_us = (*it).realtime_us; 246 247 int64_t delay_us; 248 if (when_us < 0 || when_us == INT64_MAX) { 249 delay_us = 0; 250 } else { 251 delay_us = when_us - now_us; 252 } 253 254 if (delay_us <= 0) { 255 break; 256 } 257 258 static int64_t kMaxTimeoutUs = 10000000ll; // 10 secs 259 bool timeoutCapped = false; 260 if (delay_us > kMaxTimeoutUs) { 261 ALOGW("delay_us exceeds max timeout: %lld us", delay_us); 262 263 // We'll never block for more than 10 secs, instead 264 // we will split up the full timeout into chunks of 265 // 10 secs at a time. This will also avoid overflow 266 // when converting from us to ns. 267 delay_us = kMaxTimeoutUs; 268 timeoutCapped = true; 269 } 270 271 status_t err = mQueueHeadChangedCondition.waitRelative( 272 mLock, delay_us * 1000ll); 273 274 if (!timeoutCapped && err == -ETIMEDOUT) { 275 // We finally hit the time this event is supposed to 276 // trigger. 277 now_us = ALooper::GetNowUs(); 278 break; 279 } 280 } 281 282 // The event w/ this id may have been cancelled while we're 283 // waiting for its trigger-time, in that case 284 // removeEventFromQueue_l will return NULL. 285 // Otherwise, the QueueItem will be removed 286 // from the queue and the referenced event returned. 287 event = removeEventFromQueue_l(eventID, &wakeLocked); 288 } 289 290 if (event != NULL) { 291 // Fire event with the lock NOT held. 292 event->fire(this, now_us); 293 if (wakeLocked) { 294 Mutex::Autolock autoLock(mLock); 295 releaseWakeLock_l(); 296 } 297 } 298 } 299 } 300 301 sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l( 302 event_id id, bool *wakeLocked) { 303 for (List<QueueItem>::iterator it = mQueue.begin(); 304 it != mQueue.end(); ++it) { 305 if ((*it).event->eventID() == id) { 306 sp<Event> event = (*it).event; 307 event->setEventID(0); 308 *wakeLocked = (*it).has_wakelock; 309 mQueue.erase(it); 310 return event; 311 } 312 } 313 314 ALOGW("Event %d was not found in the queue, already cancelled?", id); 315 316 return NULL; 317 } 318 319 void TimedEventQueue::acquireWakeLock_l() 320 { 321 if (mWakeLockCount++ == 0) { 322 CHECK(mWakeLockToken == 0); 323 if (mPowerManager == 0) { 324 // use checkService() to avoid blocking if power service is not up yet 325 sp<IBinder> binder = 326 defaultServiceManager()->checkService(String16("power")); 327 if (binder == 0) { 328 ALOGW("cannot connect to the power manager service"); 329 } else { 330 mPowerManager = interface_cast<IPowerManager>(binder); 331 binder->linkToDeath(mDeathRecipient); 332 } 333 } 334 if (mPowerManager != 0) { 335 sp<IBinder> binder = new BBinder(); 336 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 337 status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK, 338 binder, 339 String16("TimedEventQueue"), 340 String16("media")); 341 IPCThreadState::self()->restoreCallingIdentity(token); 342 if (status == NO_ERROR) { 343 mWakeLockToken = binder; 344 } 345 } 346 } 347 } 348 349 void TimedEventQueue::releaseWakeLock_l(bool force) 350 { 351 if (force) { 352 if (mWakeLockCount == 0) { 353 return; 354 } 355 // Force wakelock release below by setting reference count to 1. 356 mWakeLockCount = 1; 357 } 358 CHECK(mWakeLockCount != 0); 359 if (--mWakeLockCount == 0) { 360 CHECK(mWakeLockToken != 0); 361 if (mPowerManager != 0) { 362 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 363 mPowerManager->releaseWakeLock(mWakeLockToken, 0); 364 IPCThreadState::self()->restoreCallingIdentity(token); 365 } 366 mWakeLockToken.clear(); 367 } 368 } 369 370 void TimedEventQueue::clearPowerManager() 371 { 372 Mutex::Autolock _l(mLock); 373 releaseWakeLock_l(true /*force*/); 374 mPowerManager.clear(); 375 } 376 377 void TimedEventQueue::PMDeathRecipient::binderDied(const wp<IBinder>& who) 378 { 379 mQueue->clearPowerManager(); 380 } 381 382 } // namespace android 383 384