android_view_InputQueue.cpp revision 349703effce5acc53ed96f7ed8556131f0c65e18
16b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua/* 26b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * Copyright (C) 2010 The Android Open Source Project 36b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * 46b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * Licensed under the Apache License, Version 2.0 (the "License"); 56b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * you may not use this file except in compliance with the License. 66b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * You may obtain a copy of the License at 76b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * 86b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * http://www.apache.org/licenses/LICENSE-2.0 96b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * 106b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * Unless required by applicable law or agreed to in writing, software 116b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * distributed under the License is distributed on an "AS IS" BASIS, 126b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * See the License for the specific language governing permissions and 146b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua * limitations under the License. 156b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua */ 166b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 176b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#define LOG_TAG "InputQueue-JNI" 186b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 196b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua//#define LOG_NDEBUG 0 206b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 216b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua// Log debug messages about the dispatch cycle. 226b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#define DEBUG_DISPATCH_CYCLE 0 236b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 246b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua// Log debug messages about registrations. 256b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#define DEBUG_REGISTRATION 0 266b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 276b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 286b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include "JNIHelp.h" 296b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 306b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include <android_runtime/AndroidRuntime.h> 316b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include <utils/Log.h> 326b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include <utils/PollLoop.h> 336b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include <utils/KeyedVector.h> 346b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include <utils/threads.h> 356b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include <ui/InputTransport.h> 366b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include "android_os_MessageQueue.h" 376b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include "android_view_InputChannel.h" 386b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include "android_view_KeyEvent.h" 396b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua#include "android_view_MotionEvent.h" 406b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 416b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Huanamespace android { 426b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 436b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua// ---------------------------------------------------------------------------- 446b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 456b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Huastatic struct { 466b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua jclass clazz; 476b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 486b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua jmethodID dispatchKeyEvent; 496b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua jmethodID dispatchMotionEvent; 506b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua} gInputQueueClassInfo; 516b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 526b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua// ---------------------------------------------------------------------------- 536b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 546b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Huaclass NativeInputQueue { 556b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Huapublic: 56b019e89cbea221598c482b05ab68b7660b41aa23saberian NativeInputQueue(); 576b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua ~NativeInputQueue(); 586b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 596b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua status_t registerInputChannel(JNIEnv* env, jobject inputChannelObj, 606b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua jobject inputHandlerObj, jobject messageQueueObj); 616b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 626b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua status_t unregisterInputChannel(JNIEnv* env, jobject inputChannelObj); 636b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 646b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua status_t finished(JNIEnv* env, jlong finishedToken, bool ignoreSpuriousFinish); 656b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 666b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Huaprivate: 676b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua class Connection : public RefBase { 686b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua protected: 696b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua virtual ~Connection(); 706b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 716b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua public: 726b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua enum Status { 736b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua // Everything is peachy. 746b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua STATUS_NORMAL, 756b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua // The input channel has been unregistered. 766b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua STATUS_ZOMBIE 776b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua }; 786b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 796b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua Connection(const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop); 806b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 816b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua inline const char* getInputChannelName() const { return inputChannel->getName().string(); } 826b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 836b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua Status status; 846b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 856b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua sp<InputChannel> inputChannel; 866b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua InputConsumer inputConsumer; 876b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua sp<PollLoop> pollLoop; 886b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua jobject inputHandlerObjGlobal; 896b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua PreallocatedInputEventFactory inputEventFactory; 906b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 916b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua // The sequence number of the current event being dispatched. 926b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua // This is used as part of the finished token as a way to determine whether the finished 936b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua // token is still valid before sending a finished signal back to the publisher. 94b019e89cbea221598c482b05ab68b7660b41aa23saberian uint32_t messageSeqNum; 95b019e89cbea221598c482b05ab68b7660b41aa23saberian 96b019e89cbea221598c482b05ab68b7660b41aa23saberian // True if a message has been received from the publisher but not yet finished. 97b019e89cbea221598c482b05ab68b7660b41aa23saberian bool messageInProgress; 98b019e89cbea221598c482b05ab68b7660b41aa23saberian }; 99b019e89cbea221598c482b05ab68b7660b41aa23saberian 100b019e89cbea221598c482b05ab68b7660b41aa23saberian Mutex mLock; 101b019e89cbea221598c482b05ab68b7660b41aa23saberian KeyedVector<int32_t, sp<Connection> > mConnectionsByReceiveFd; 102b019e89cbea221598c482b05ab68b7660b41aa23saberian 103b019e89cbea221598c482b05ab68b7660b41aa23saberian static void handleInputChannelDisposed(JNIEnv* env, 104b019e89cbea221598c482b05ab68b7660b41aa23saberian jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data); 105b019e89cbea221598c482b05ab68b7660b41aa23saberian 106b019e89cbea221598c482b05ab68b7660b41aa23saberian static bool handleReceiveCallback(int receiveFd, int events, void* data); 1076b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 1086b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua static jlong generateFinishedToken(int32_t receiveFd, int32_t messageSeqNum); 1096b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 1106b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua static void parseFinishedToken(jlong finishedToken, 1116b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua int32_t* outReceiveFd, uint32_t* outMessageIndex); 1126b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua}; 1136b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 1146b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua// ---------------------------------------------------------------------------- 1156b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua 1166b4eebc73439cbc3ddfb547444a341d1f9be7996Wei HuaNativeInputQueue::NativeInputQueue() { 1176b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua} 118b019e89cbea221598c482b05ab68b7660b41aa23saberian 119b019e89cbea221598c482b05ab68b7660b41aa23saberianNativeInputQueue::~NativeInputQueue() { 120b019e89cbea221598c482b05ab68b7660b41aa23saberian} 121b019e89cbea221598c482b05ab68b7660b41aa23saberian 122b019e89cbea221598c482b05ab68b7660b41aa23saberianstatus_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChannelObj, 123b019e89cbea221598c482b05ab68b7660b41aa23saberian jobject inputHandlerObj, jobject messageQueueObj) { 124b019e89cbea221598c482b05ab68b7660b41aa23saberian sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, 125b019e89cbea221598c482b05ab68b7660b41aa23saberian inputChannelObj); 126b019e89cbea221598c482b05ab68b7660b41aa23saberian if (inputChannel == NULL) { 1276b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua LOGW("Input channel is not initialized."); 1286b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua return BAD_VALUE; 129b019e89cbea221598c482b05ab68b7660b41aa23saberian } 130b019e89cbea221598c482b05ab68b7660b41aa23saberian 131b019e89cbea221598c482b05ab68b7660b41aa23saberian#if DEBUG_REGISTRATION 132b019e89cbea221598c482b05ab68b7660b41aa23saberian LOGD("channel '%s' - Registered", inputChannel->getName().string()); 133b019e89cbea221598c482b05ab68b7660b41aa23saberian#endif 134b019e89cbea221598c482b05ab68b7660b41aa23saberian 135984e52f31d596840cfa51b1238e1c43d2e1918f8saberian sp<PollLoop> pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueueObj); 136b019e89cbea221598c482b05ab68b7660b41aa23saberian 137b019e89cbea221598c482b05ab68b7660b41aa23saberian int receiveFd; 1386b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua { // acquire lock 1396b4eebc73439cbc3ddfb547444a341d1f9be7996Wei Hua AutoMutex _l(mLock); 140 141 receiveFd = inputChannel->getReceivePipeFd(); 142 if (mConnectionsByReceiveFd.indexOfKey(receiveFd) >= 0) { 143 LOGW("Attempted to register already registered input channel '%s'", 144 inputChannel->getName().string()); 145 return BAD_VALUE; 146 } 147 148 sp<Connection> connection = new Connection(inputChannel, pollLoop); 149 status_t result = connection->inputConsumer.initialize(); 150 if (result) { 151 LOGW("Failed to initialize input consumer for input channel '%s', status=%d", 152 inputChannel->getName().string(), result); 153 return result; 154 } 155 156 connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj); 157 158 mConnectionsByReceiveFd.add(receiveFd, connection); 159 } // release lock 160 161 android_view_InputChannel_setDisposeCallback(env, inputChannelObj, 162 handleInputChannelDisposed, this); 163 164 pollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this); 165 return OK; 166} 167 168status_t NativeInputQueue::unregisterInputChannel(JNIEnv* env, jobject inputChannelObj) { 169 sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, 170 inputChannelObj); 171 if (inputChannel == NULL) { 172 LOGW("Input channel is not initialized."); 173 return BAD_VALUE; 174 } 175 176#if DEBUG_REGISTRATION 177 LOGD("channel '%s' - Unregistered", inputChannel->getName().string()); 178#endif 179 180 int32_t receiveFd; 181 sp<Connection> connection; 182 { // acquire lock 183 AutoMutex _l(mLock); 184 185 receiveFd = inputChannel->getReceivePipeFd(); 186 ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd); 187 if (connectionIndex < 0) { 188 LOGW("Attempted to unregister already unregistered input channel '%s'", 189 inputChannel->getName().string()); 190 return BAD_VALUE; 191 } 192 193 connection = mConnectionsByReceiveFd.valueAt(connectionIndex); 194 mConnectionsByReceiveFd.removeItemsAt(connectionIndex); 195 196 connection->status = Connection::STATUS_ZOMBIE; 197 198 env->DeleteGlobalRef(connection->inputHandlerObjGlobal); 199 connection->inputHandlerObjGlobal = NULL; 200 } // release lock 201 202 android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL); 203 204 connection->pollLoop->removeCallback(receiveFd); 205 return OK; 206} 207 208status_t NativeInputQueue::finished(JNIEnv* env, jlong finishedToken, bool ignoreSpuriousFinish) { 209 int32_t receiveFd; 210 uint32_t messageSeqNum; 211 parseFinishedToken(finishedToken, &receiveFd, &messageSeqNum); 212 213 { // acquire lock 214 AutoMutex _l(mLock); 215 216 ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd); 217 if (connectionIndex < 0) { 218 if (! ignoreSpuriousFinish) { 219 LOGW("Attempted to finish input on channel that is no longer registered."); 220 } 221 return DEAD_OBJECT; 222 } 223 224 sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); 225 if (messageSeqNum != connection->messageSeqNum || ! connection->messageInProgress) { 226 if (! ignoreSpuriousFinish) { 227 LOGW("Attempted to finish input twice on channel '%s'.", 228 connection->getInputChannelName()); 229 } 230 return INVALID_OPERATION; 231 } 232 233 connection->messageInProgress = false; 234 235 status_t status = connection->inputConsumer.sendFinishedSignal(); 236 if (status) { 237 LOGW("Failed to send finished signal on channel '%s'. status=%d", 238 connection->getInputChannelName(), status); 239 return status; 240 } 241 242#if DEBUG_DISPATCH_CYCLE 243 LOGD("channel '%s' ~ Finished event.", 244 connection->getInputChannelName()); 245#endif 246 } // release lock 247 248 return OK; 249} 250 251void NativeInputQueue::handleInputChannelDisposed(JNIEnv* env, 252 jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data) { 253 LOGW("Input channel object '%s' was disposed without first being unregistered with " 254 "the input queue!", inputChannel->getName().string()); 255 256 NativeInputQueue* q = static_cast<NativeInputQueue*>(data); 257 q->unregisterInputChannel(env, inputChannelObj); 258} 259 260bool NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) { 261 NativeInputQueue* q = static_cast<NativeInputQueue*>(data); 262 JNIEnv* env = AndroidRuntime::getJNIEnv(); 263 264 sp<Connection> connection; 265 InputEvent* inputEvent; 266 jobject inputHandlerObjLocal; 267 jlong finishedToken; 268 { // acquire lock 269 AutoMutex _l(q->mLock); 270 271 ssize_t connectionIndex = q->mConnectionsByReceiveFd.indexOfKey(receiveFd); 272 if (connectionIndex < 0) { 273 LOGE("Received spurious receive callback for unknown input channel. " 274 "fd=%d, events=0x%x", receiveFd, events); 275 return false; // remove the callback 276 } 277 278 connection = q->mConnectionsByReceiveFd.valueAt(connectionIndex); 279 if (events & (POLLERR | POLLHUP | POLLNVAL)) { 280 LOGE("channel '%s' ~ Publisher closed input channel or an error occurred. " 281 "events=0x%x", connection->getInputChannelName(), events); 282 return false; // remove the callback 283 } 284 285 if (! (events & POLLIN)) { 286 LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " 287 "events=0x%x", connection->getInputChannelName(), events); 288 return true; 289 } 290 291 status_t status = connection->inputConsumer.receiveDispatchSignal(); 292 if (status) { 293 LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d", 294 connection->getInputChannelName(), status); 295 return false; // remove the callback 296 } 297 298 if (connection->messageInProgress) { 299 LOGW("channel '%s' ~ Publisher sent spurious dispatch signal.", 300 connection->getInputChannelName()); 301 return true; 302 } 303 304 status = connection->inputConsumer.consume(& connection->inputEventFactory, & inputEvent); 305 if (status) { 306 LOGW("channel '%s' ~ Failed to consume input event. status=%d", 307 connection->getInputChannelName(), status); 308 connection->inputConsumer.sendFinishedSignal(); 309 return true; 310 } 311 312 connection->messageInProgress = true; 313 connection->messageSeqNum += 1; 314 315 finishedToken = generateFinishedToken(receiveFd, connection->messageSeqNum); 316 317 inputHandlerObjLocal = env->NewLocalRef(connection->inputHandlerObjGlobal); 318 } // release lock 319 320 // Invoke the handler outside of the lock. 321 // 322 // Note: inputEvent is stored in a field of the connection object which could potentially 323 // become disposed due to the input channel being unregistered concurrently. 324 // For this reason, we explicitly keep the connection object alive by holding 325 // a strong pointer to it within this scope. We also grabbed a local reference to 326 // the input handler object itself for the same reason. 327 328 int32_t inputEventType = inputEvent->getType(); 329 int32_t inputEventNature = inputEvent->getNature(); 330 331 jobject inputEventObj; 332 jmethodID dispatchMethodId; 333 switch (inputEventType) { 334 case INPUT_EVENT_TYPE_KEY: 335#if DEBUG_DISPATCH_CYCLE 336 LOGD("channel '%s' ~ Received key event.", connection->getInputChannelName()); 337#endif 338 inputEventObj = android_view_KeyEvent_fromNative(env, 339 static_cast<KeyEvent*>(inputEvent)); 340 dispatchMethodId = gInputQueueClassInfo.dispatchKeyEvent; 341 break; 342 343 case INPUT_EVENT_TYPE_MOTION: 344#if DEBUG_DISPATCH_CYCLE 345 LOGD("channel '%s' ~ Received motion event.", connection->getInputChannelName()); 346#endif 347 inputEventObj = android_view_MotionEvent_fromNative(env, 348 static_cast<MotionEvent*>(inputEvent)); 349 dispatchMethodId = gInputQueueClassInfo.dispatchMotionEvent; 350 break; 351 352 default: 353 assert(false); // InputConsumer should prevent this from ever happening 354 inputEventObj = NULL; 355 } 356 357 if (! inputEventObj) { 358 LOGW("channel '%s' ~ Failed to obtain DVM event object.", 359 connection->getInputChannelName()); 360 env->DeleteLocalRef(inputHandlerObjLocal); 361 q->finished(env, finishedToken, false); 362 return true; 363 } 364 365#if DEBUG_DISPATCH_CYCLE 366 LOGD("Invoking input handler."); 367#endif 368 env->CallStaticVoidMethod(gInputQueueClassInfo.clazz, 369 dispatchMethodId, inputHandlerObjLocal, inputEventObj, 370 jint(inputEventNature), jlong(finishedToken)); 371#if DEBUG_DISPATCH_CYCLE 372 LOGD("Returned from input handler."); 373#endif 374 375 if (env->ExceptionCheck()) { 376 LOGE("An exception occurred while invoking the input handler for an event."); 377 LOGE_EX(env); 378 env->ExceptionClear(); 379 380 q->finished(env, finishedToken, true /*ignoreSpuriousFinish*/); 381 } 382 383 env->DeleteLocalRef(inputEventObj); 384 env->DeleteLocalRef(inputHandlerObjLocal); 385 return true; 386} 387 388jlong NativeInputQueue::generateFinishedToken(int32_t receiveFd, int32_t messageSeqNum) { 389 return (jlong(receiveFd) << 32) | jlong(messageSeqNum); 390} 391 392void NativeInputQueue::parseFinishedToken(jlong finishedToken, 393 int32_t* outReceiveFd, uint32_t* outMessageIndex) { 394 *outReceiveFd = int32_t(finishedToken >> 32); 395 *outMessageIndex = uint32_t(finishedToken & 0xffffffff); 396} 397 398// ---------------------------------------------------------------------------- 399 400NativeInputQueue::Connection::Connection(const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop) : 401 status(STATUS_NORMAL), inputChannel(inputChannel), inputConsumer(inputChannel), 402 pollLoop(pollLoop), inputHandlerObjGlobal(NULL), 403 messageSeqNum(0), messageInProgress(false) { 404} 405 406NativeInputQueue::Connection::~Connection() { 407} 408 409// ---------------------------------------------------------------------------- 410 411static NativeInputQueue gNativeInputQueue; 412 413static void android_view_InputQueue_nativeRegisterInputChannel(JNIEnv* env, jclass clazz, 414 jobject inputChannelObj, jobject inputHandlerObj, jobject messageQueueObj) { 415 status_t status = gNativeInputQueue.registerInputChannel( 416 env, inputChannelObj, inputHandlerObj, messageQueueObj); 417 if (status) { 418 jniThrowRuntimeException(env, "Failed to register input channel. " 419 "Check logs for details."); 420 } 421} 422 423static void android_view_InputQueue_nativeUnregisterInputChannel(JNIEnv* env, jclass clazz, 424 jobject inputChannelObj) { 425 status_t status = gNativeInputQueue.unregisterInputChannel(env, inputChannelObj); 426 if (status) { 427 jniThrowRuntimeException(env, "Failed to unregister input channel. " 428 "Check logs for details."); 429 } 430} 431 432static void android_view_InputQueue_nativeFinished(JNIEnv* env, jclass clazz, 433 jlong finishedToken) { 434 status_t status = gNativeInputQueue.finished( 435 env, finishedToken, false /*ignoreSpuriousFinish*/); 436 if (status) { 437 jniThrowRuntimeException(env, "Failed to finish input event. " 438 "Check logs for details."); 439 } 440} 441 442// ---------------------------------------------------------------------------- 443 444static JNINativeMethod gInputQueueMethods[] = { 445 /* name, signature, funcPtr */ 446 { "nativeRegisterInputChannel", 447 "(Landroid/view/InputChannel;Landroid/view/InputHandler;Landroid/os/MessageQueue;)V", 448 (void*)android_view_InputQueue_nativeRegisterInputChannel }, 449 { "nativeUnregisterInputChannel", 450 "(Landroid/view/InputChannel;)V", 451 (void*)android_view_InputQueue_nativeUnregisterInputChannel }, 452 { "nativeFinished", "(J)V", 453 (void*)android_view_InputQueue_nativeFinished } 454}; 455 456#define FIND_CLASS(var, className) \ 457 var = env->FindClass(className); \ 458 LOG_FATAL_IF(! var, "Unable to find class " className); \ 459 var = jclass(env->NewGlobalRef(var)); 460 461#define GET_STATIC_METHOD_ID(var, clazz, methodName, methodDescriptor) \ 462 var = env->GetStaticMethodID(clazz, methodName, methodDescriptor); \ 463 LOG_FATAL_IF(! var, "Unable to find static method " methodName); 464 465int register_android_view_InputQueue(JNIEnv* env) { 466 int res = jniRegisterNativeMethods(env, "android/view/InputQueue", 467 gInputQueueMethods, NELEM(gInputQueueMethods)); 468 LOG_FATAL_IF(res < 0, "Unable to register native methods."); 469 470 FIND_CLASS(gInputQueueClassInfo.clazz, "android/view/InputQueue"); 471 472 GET_STATIC_METHOD_ID(gInputQueueClassInfo.dispatchKeyEvent, gInputQueueClassInfo.clazz, 473 "dispatchKeyEvent", 474 "(Landroid/view/InputHandler;Landroid/view/KeyEvent;IJ)V"); 475 476 GET_STATIC_METHOD_ID(gInputQueueClassInfo.dispatchMotionEvent, gInputQueueClassInfo.clazz, 477 "dispatchMotionEvent", 478 "(Landroid/view/InputHandler;Landroid/view/MotionEvent;IJ)V"); 479 return 0; 480} 481 482} // namespace android 483