Merge "Fix spurious ANRs in native activities."
This commit is contained in:
@@ -162,12 +162,12 @@ int32_t AInputQueue::hasEvents() {
|
||||
int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
|
||||
*outEvent = NULL;
|
||||
|
||||
bool finishNow = false;
|
||||
|
||||
char byteread;
|
||||
ssize_t nRead = read(mDispatchKeyRead, &byteread, 1);
|
||||
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
if (nRead == 1) {
|
||||
mLock.lock();
|
||||
if (mDispatchingKeys.size() > 0) {
|
||||
KeyEvent* kevent = mDispatchingKeys[0];
|
||||
*outEvent = kevent;
|
||||
@@ -178,6 +178,8 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
|
||||
inflight.finishSeq = 0;
|
||||
mInFlightEvents.push(inflight);
|
||||
}
|
||||
|
||||
bool finishNow = false;
|
||||
if (mFinishPreDispatches.size() > 0) {
|
||||
finish_pre_dispatch finish(mFinishPreDispatches[0]);
|
||||
mFinishPreDispatches.removeAt(0);
|
||||
@@ -193,7 +195,6 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
|
||||
ALOGW("getEvent couldn't find inflight for seq %d", finish.seq);
|
||||
}
|
||||
}
|
||||
mLock.unlock();
|
||||
|
||||
if (finishNow) {
|
||||
finishEvent(*outEvent, true, false);
|
||||
@@ -206,7 +207,8 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
|
||||
|
||||
uint32_t consumerSeq;
|
||||
InputEvent* myEvent = NULL;
|
||||
status_t res = mConsumer.consume(this, true /*consumeBatches*/, &consumerSeq, &myEvent);
|
||||
status_t res = mConsumer.consume(&mPooledInputEventFactory, true /*consumeBatches*/,
|
||||
&consumerSeq, &myEvent);
|
||||
if (res != android::OK) {
|
||||
if (res != android::WOULD_BLOCK) {
|
||||
ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
|
||||
@@ -215,6 +217,10 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mConsumer.hasDeferredEvent()) {
|
||||
wakeupDispatchLocked();
|
||||
}
|
||||
|
||||
in_flight_event inflight;
|
||||
inflight.event = myEvent;
|
||||
inflight.seq = -1;
|
||||
@@ -255,7 +261,8 @@ void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultH
|
||||
return;
|
||||
}
|
||||
|
||||
mLock.lock();
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
const size_t N = mInFlightEvents.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
const in_flight_event& inflight(mInFlightEvents[i]);
|
||||
@@ -267,111 +274,82 @@ void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultH
|
||||
mConsumer.getChannel()->getName().string(), res);
|
||||
}
|
||||
}
|
||||
if (static_cast<InputEvent*>(event)->getType() == AINPUT_EVENT_TYPE_KEY) {
|
||||
mAvailKeyEvents.push(static_cast<KeyEvent*>(event));
|
||||
} else {
|
||||
mAvailMotionEvents.push(static_cast<MotionEvent*>(event));
|
||||
}
|
||||
mPooledInputEventFactory.recycle(static_cast<InputEvent*>(event));
|
||||
mInFlightEvents.removeAt(i);
|
||||
mLock.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
mLock.unlock();
|
||||
|
||||
|
||||
ALOGW("finishEvent called for unknown event: %p", event);
|
||||
}
|
||||
|
||||
void AInputQueue::dispatchEvent(android::KeyEvent* event) {
|
||||
mLock.lock();
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(),
|
||||
mDispatchKeyWrite);
|
||||
mDispatchingKeys.add(event);
|
||||
wakeupDispatch();
|
||||
mLock.unlock();
|
||||
wakeupDispatchLocked();
|
||||
}
|
||||
|
||||
void AInputQueue::finishPreDispatch(int seq, bool handled) {
|
||||
mLock.lock();
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
LOG_TRACE("finishPreDispatch: seq=%d handled=%d\n", seq, handled ? 1 : 0);
|
||||
finish_pre_dispatch finish;
|
||||
finish.seq = seq;
|
||||
finish.handled = handled;
|
||||
mFinishPreDispatches.add(finish);
|
||||
wakeupDispatch();
|
||||
mLock.unlock();
|
||||
wakeupDispatchLocked();
|
||||
}
|
||||
|
||||
KeyEvent* AInputQueue::consumeUnhandledEvent() {
|
||||
KeyEvent* event = NULL;
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
mLock.lock();
|
||||
KeyEvent* event = NULL;
|
||||
if (mUnhandledKeys.size() > 0) {
|
||||
event = mUnhandledKeys[0];
|
||||
mUnhandledKeys.removeAt(0);
|
||||
}
|
||||
mLock.unlock();
|
||||
|
||||
LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
KeyEvent* AInputQueue::consumePreDispatchingEvent(int* outSeq) {
|
||||
KeyEvent* event = NULL;
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
mLock.lock();
|
||||
KeyEvent* event = NULL;
|
||||
if (mPreDispatchingKeys.size() > 0) {
|
||||
const in_flight_event& inflight(mPreDispatchingKeys[0]);
|
||||
event = static_cast<KeyEvent*>(inflight.event);
|
||||
*outSeq = inflight.seq;
|
||||
mPreDispatchingKeys.removeAt(0);
|
||||
}
|
||||
mLock.unlock();
|
||||
|
||||
LOG_TRACE("consumePreDispatchingEvent: KeyEvent=%p", event);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
KeyEvent* AInputQueue::createKeyEvent() {
|
||||
mLock.lock();
|
||||
KeyEvent* event;
|
||||
if (mAvailKeyEvents.size() <= 0) {
|
||||
event = new KeyEvent();
|
||||
} else {
|
||||
event = mAvailKeyEvents.top();
|
||||
mAvailKeyEvents.pop();
|
||||
}
|
||||
mLock.unlock();
|
||||
return event;
|
||||
}
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
MotionEvent* AInputQueue::createMotionEvent() {
|
||||
mLock.lock();
|
||||
MotionEvent* event;
|
||||
if (mAvailMotionEvents.size() <= 0) {
|
||||
event = new MotionEvent();
|
||||
} else {
|
||||
event = mAvailMotionEvents.top();
|
||||
mAvailMotionEvents.pop();
|
||||
}
|
||||
mLock.unlock();
|
||||
return event;
|
||||
return mPooledInputEventFactory.createKeyEvent();
|
||||
}
|
||||
|
||||
void AInputQueue::doUnhandledKey(KeyEvent* keyEvent) {
|
||||
mLock.lock();
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
LOG_TRACE("Unhandled key: pending=%d write=%d\n", mUnhandledKeys.size(), mWorkWrite);
|
||||
if (mUnhandledKeys.size() <= 0 && mWorkWrite >= 0) {
|
||||
write_work(mWorkWrite, CMD_DEF_KEY);
|
||||
}
|
||||
mUnhandledKeys.add(keyEvent);
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) {
|
||||
mLock.lock();
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
LOG_TRACE("preDispatch key: pending=%d write=%d\n", mPreDispatchingKeys.size(), mWorkWrite);
|
||||
const size_t N = mInFlightEvents.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
@@ -380,7 +358,6 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) {
|
||||
if (inflight.seq >= 0) {
|
||||
// This event has already been pre-dispatched!
|
||||
LOG_TRACE("Event already pre-dispatched!");
|
||||
mLock.unlock();
|
||||
return false;
|
||||
}
|
||||
mSeq++;
|
||||
@@ -391,7 +368,6 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) {
|
||||
write_work(mWorkWrite, CMD_DEF_KEY);
|
||||
}
|
||||
mPreDispatchingKeys.add(inflight);
|
||||
mLock.unlock();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -400,7 +376,7 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void AInputQueue::wakeupDispatch() {
|
||||
void AInputQueue::wakeupDispatchLocked() {
|
||||
restart:
|
||||
char dummy = 0;
|
||||
int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy));
|
||||
|
||||
@@ -65,7 +65,7 @@ extern void android_NativeActivity_hideSoftInput(
|
||||
* b. Java sends event through default key handler.
|
||||
* c. event is finished.
|
||||
*/
|
||||
struct AInputQueue : public android::InputEventFactoryInterface {
|
||||
struct AInputQueue {
|
||||
public:
|
||||
/* Creates a consumer associated with an input channel. */
|
||||
explicit AInputQueue(const android::sp<android::InputChannel>& channel, int workWrite);
|
||||
@@ -96,16 +96,16 @@ public:
|
||||
android::KeyEvent* consumeUnhandledEvent();
|
||||
android::KeyEvent* consumePreDispatchingEvent(int* outSeq);
|
||||
|
||||
virtual android::KeyEvent* createKeyEvent();
|
||||
virtual android::MotionEvent* createMotionEvent();
|
||||
android::KeyEvent* createKeyEvent();
|
||||
|
||||
int mWorkWrite;
|
||||
|
||||
private:
|
||||
void doUnhandledKey(android::KeyEvent* keyEvent);
|
||||
bool preDispatchKey(android::KeyEvent* keyEvent);
|
||||
void wakeupDispatch();
|
||||
void wakeupDispatchLocked();
|
||||
|
||||
android::PooledInputEventFactory mPooledInputEventFactory;
|
||||
android::InputConsumer mConsumer;
|
||||
android::sp<android::Looper> mLooper;
|
||||
|
||||
@@ -127,11 +127,6 @@ private:
|
||||
|
||||
int mSeq;
|
||||
|
||||
// Cache of previously allocated key events.
|
||||
android::Vector<android::KeyEvent*> mAvailKeyEvents;
|
||||
// Cache of previously allocated motion events.
|
||||
android::Vector<android::MotionEvent*> mAvailMotionEvents;
|
||||
|
||||
// All input events that are actively being processed.
|
||||
android::Vector<in_flight_event> mInFlightEvents;
|
||||
|
||||
|
||||
@@ -615,6 +615,26 @@ private:
|
||||
MotionEvent mMotionEvent;
|
||||
};
|
||||
|
||||
/*
|
||||
* An input event factory implementation that maintains a pool of input events.
|
||||
*/
|
||||
class PooledInputEventFactory : public InputEventFactoryInterface {
|
||||
public:
|
||||
PooledInputEventFactory(size_t maxPoolSize = 20);
|
||||
virtual ~PooledInputEventFactory();
|
||||
|
||||
virtual KeyEvent* createKeyEvent();
|
||||
virtual MotionEvent* createMotionEvent();
|
||||
|
||||
void recycle(InputEvent* event);
|
||||
|
||||
private:
|
||||
const size_t mMaxPoolSize;
|
||||
|
||||
Vector<KeyEvent*> mKeyEventPool;
|
||||
Vector<MotionEvent*> mMotionEventPool;
|
||||
};
|
||||
|
||||
/*
|
||||
* Calculates the velocity of pointer movements over time.
|
||||
*/
|
||||
|
||||
@@ -292,7 +292,29 @@ public:
|
||||
*/
|
||||
status_t sendFinishedSignal(uint32_t seq, bool handled);
|
||||
|
||||
/* Returns true if there is a pending batch. */
|
||||
/* Returns true if there is a deferred event waiting.
|
||||
*
|
||||
* Should be called after calling consume() to determine whether the consumer
|
||||
* has a deferred event to be processed. Deferred events are somewhat special in
|
||||
* that they have already been removed from the input channel. If the input channel
|
||||
* becomes empty, the client may need to do extra work to ensure that it processes
|
||||
* the deferred event despite the fact that the inptu channel's file descriptor
|
||||
* is not readable.
|
||||
*
|
||||
* One option is simply to call consume() in a loop until it returns WOULD_BLOCK.
|
||||
* This guarantees that all deferred events will be processed.
|
||||
*
|
||||
* Alternately, the caller can call hasDeferredEvent() to determine whether there is
|
||||
* a deferred event waiting and then ensure that its event loop wakes up at least
|
||||
* one more time to consume the deferred event.
|
||||
*/
|
||||
bool hasDeferredEvent() const;
|
||||
|
||||
/* Returns true if there is a pending batch.
|
||||
*
|
||||
* Should be called after calling consume() with consumeBatches == false to determine
|
||||
* whether consume() should be called again later on with consumeBatches == true.
|
||||
*/
|
||||
bool hasPendingBatch() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -683,6 +683,58 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
|
||||
}
|
||||
|
||||
|
||||
// --- PooledInputEventFactory ---
|
||||
|
||||
PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
|
||||
mMaxPoolSize(maxPoolSize) {
|
||||
}
|
||||
|
||||
PooledInputEventFactory::~PooledInputEventFactory() {
|
||||
for (size_t i = 0; i < mKeyEventPool.size(); i++) {
|
||||
delete mKeyEventPool.itemAt(i);
|
||||
}
|
||||
for (size_t i = 0; i < mMotionEventPool.size(); i++) {
|
||||
delete mMotionEventPool.itemAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
KeyEvent* PooledInputEventFactory::createKeyEvent() {
|
||||
if (!mKeyEventPool.isEmpty()) {
|
||||
KeyEvent* event = mKeyEventPool.top();
|
||||
mKeyEventPool.pop();
|
||||
return event;
|
||||
}
|
||||
return new KeyEvent();
|
||||
}
|
||||
|
||||
MotionEvent* PooledInputEventFactory::createMotionEvent() {
|
||||
if (!mMotionEventPool.isEmpty()) {
|
||||
MotionEvent* event = mMotionEventPool.top();
|
||||
mMotionEventPool.pop();
|
||||
return event;
|
||||
}
|
||||
return new MotionEvent();
|
||||
}
|
||||
|
||||
void PooledInputEventFactory::recycle(InputEvent* event) {
|
||||
switch (event->getType()) {
|
||||
case AINPUT_EVENT_TYPE_KEY:
|
||||
if (mKeyEventPool.size() < mMaxPoolSize) {
|
||||
mKeyEventPool.push(static_cast<KeyEvent*>(event));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case AINPUT_EVENT_TYPE_MOTION:
|
||||
if (mMotionEventPool.size() < mMaxPoolSize) {
|
||||
mMotionEventPool.push(static_cast<MotionEvent*>(event));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
delete event;
|
||||
}
|
||||
|
||||
|
||||
// --- VelocityTracker ---
|
||||
|
||||
const uint32_t VelocityTracker::DEFAULT_DEGREE;
|
||||
|
||||
@@ -527,6 +527,10 @@ status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled)
|
||||
return mChannel->sendMessage(&msg);
|
||||
}
|
||||
|
||||
bool InputConsumer::hasDeferredEvent() const {
|
||||
return mMsgDeferred;
|
||||
}
|
||||
|
||||
bool InputConsumer::hasPendingBatch() const {
|
||||
return !mBatches.isEmpty();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user