EventThread.cpp revision 478ae5eb5a0047e1b2988c896cff6363b455ee50
1/* 2 * Copyright (C) 2011 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#include <stdint.h> 18#include <sys/types.h> 19 20#include <gui/IDisplayEventConnection.h> 21#include <gui/DisplayEventReceiver.h> 22 23#include <utils/Errors.h> 24 25#include "DisplayHardware/DisplayHardware.h" 26#include "DisplayEventConnection.h" 27#include "EventThread.h" 28#include "SurfaceFlinger.h" 29 30// --------------------------------------------------------------------------- 31 32namespace android { 33 34// --------------------------------------------------------------------------- 35 36EventThread::EventThread(const sp<SurfaceFlinger>& flinger) 37 : mFlinger(flinger), 38 mHw(flinger->graphicPlane(0).displayHardware()), 39 mDeliveredEvents(0) 40{ 41} 42 43void EventThread::onFirstRef() { 44 run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); 45} 46 47status_t EventThread::registerDisplayEventConnection( 48 const sp<DisplayEventConnection>& connection) { 49 Mutex::Autolock _l(mLock); 50 ConnectionInfo info; 51 mDisplayEventConnections.add(connection, info); 52 mCondition.signal(); 53 return NO_ERROR; 54} 55 56status_t EventThread::unregisterDisplayEventConnection( 57 const wp<DisplayEventConnection>& connection) { 58 Mutex::Autolock _l(mLock); 59 mDisplayEventConnections.removeItem(connection); 60 mCondition.signal(); 61 return NO_ERROR; 62} 63 64void EventThread::removeDisplayEventConnection( 65 const wp<DisplayEventConnection>& connection) { 66 Mutex::Autolock _l(mLock); 67 mDisplayEventConnections.removeItem(connection); 68} 69 70EventThread::ConnectionInfo* EventThread::getConnectionInfoLocked( 71 const wp<DisplayEventConnection>& connection) { 72 ssize_t index = mDisplayEventConnections.indexOfKey(connection); 73 if (index < 0) return NULL; 74 return &mDisplayEventConnections.editValueAt(index); 75} 76 77void EventThread::setVsyncRate(uint32_t count, 78 const wp<DisplayEventConnection>& connection) { 79 if (int32_t(count) >= 0) { // server must protect against bad params 80 Mutex::Autolock _l(mLock); 81 ConnectionInfo* info = getConnectionInfoLocked(connection); 82 if (info) { 83 info->count = (count == 0) ? -1 : count; 84 mCondition.signal(); 85 } 86 } 87} 88 89void EventThread::requestNextVsync( 90 const wp<DisplayEventConnection>& connection) { 91 Mutex::Autolock _l(mLock); 92 ConnectionInfo* info = getConnectionInfoLocked(connection); 93 if (info) { 94 if (info->count < 0) { 95 info->count = 0; 96 } 97 mCondition.signal(); 98 } 99} 100 101bool EventThread::threadLoop() { 102 103 nsecs_t timestamp; 104 DisplayEventReceiver::Event vsync; 105 KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > displayEventConnections; 106 107 { // scope for the lock 108 Mutex::Autolock _l(mLock); 109 do { 110 // wait for listeners 111 do { 112 bool waitForNextVsync = false; 113 size_t count = mDisplayEventConnections.size(); 114 for (size_t i=0 ; i<count ; i++) { 115 const ConnectionInfo& info( 116 mDisplayEventConnections.valueAt(i)); 117 if (info.count >= 1) { 118 // continuous mode 119 waitForNextVsync = true; 120 } else { 121 // one-shot event 122 if (info.count >= -1) { 123 ConnectionInfo& info( 124 mDisplayEventConnections.editValueAt(i)); 125 info.count--; 126 if (info.count == -1) { 127 // fired this time around 128 waitForNextVsync = true; 129 } 130 } 131 } 132 } 133 134 if (waitForNextVsync) 135 break; 136 137 mCondition.wait(mLock); 138 } while(true); 139 140 // wait for vsync 141 mLock.unlock(); 142 timestamp = mHw.waitForVSync(); 143 mLock.lock(); 144 mDeliveredEvents++; 145 146 // make sure we still have some listeners 147 } while (!mDisplayEventConnections.size()); 148 149 // dispatch vsync events to listeners... 150 vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; 151 vsync.header.timestamp = timestamp; 152 vsync.vsync.count = mDeliveredEvents; 153 154 // make a copy of our connection list, so we can 155 // dispatch events without holding mLock 156 displayEventConnections = mDisplayEventConnections; 157 } 158 159 const size_t count = displayEventConnections.size(); 160 for (size_t i=0 ; i<count ; i++) { 161 sp<DisplayEventConnection> conn(displayEventConnections.keyAt(i).promote()); 162 // make sure the connection didn't die 163 if (conn != NULL) { 164 165 const ConnectionInfo& info( 166 displayEventConnections.valueAt(i)); 167 168 if ((info.count > 1) && (mDeliveredEvents % info.count)) { 169 // continuous event, but not time to send this event yet 170 continue; 171 } else if (info.count < -1) { 172 // disabled event 173 continue; 174 } else if (info.count == 0) { 175 // impossible by construction. but we prefer to be safe. 176 continue; 177 } 178 179 // here, either: 180 // count = -1 : one-shot scheduled this time around 181 // count = 1 : continuous not rate-limited 182 // count > 1 : continuous, rate-limited 183 // Note: count == 0 is not possible by construction 184 185 status_t err = conn->postEvent(vsync); 186 if (err == -EAGAIN || err == -EWOULDBLOCK) { 187 // The destination doesn't accept events anymore, it's probably 188 // full. For now, we just drop the events on the floor. 189 // Note that some events cannot be dropped and would have to be 190 // re-sent later. Right-now we don't have the ability to do 191 // this, but it doesn't matter for VSYNC. 192 } else if (err < 0) { 193 // handle any other error on the pipe as fatal. the only 194 // reasonable thing to do is to clean-up this connection. 195 // The most common error we'll get here is -EPIPE. 196 removeDisplayEventConnection(displayEventConnections.keyAt(i)); 197 } 198 } else { 199 // somehow the connection is dead, but we still have it in our list 200 // just clean the list. 201 removeDisplayEventConnection(displayEventConnections.keyAt(i)); 202 } 203 } 204 205 // clear all our references without holding mLock 206 displayEventConnections.clear(); 207 208 return true; 209} 210 211status_t EventThread::readyToRun() { 212 LOGI("EventThread ready to run."); 213 return NO_ERROR; 214} 215 216void EventThread::dump(String8& result, char* buffer, size_t SIZE) const { 217 Mutex::Autolock _l(mLock); 218 result.append("VSYNC state:\n"); 219 snprintf(buffer, SIZE, " numListeners=%u, events-delivered: %u\n", 220 mDisplayEventConnections.size(), mDeliveredEvents); 221 result.append(buffer); 222} 223 224// --------------------------------------------------------------------------- 225 226}; // namespace android 227