summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-03-13 15:00:09 -0700
committerJeff Brown <jeffbrown@google.com>2012-03-13 15:00:09 -0700
commit2b6c32ca4177f1a97307f9cbd81ca485df28762c (patch)
treeabc217f8ff191ce1ecc7c4eb9b51185b6d47625d /include
parentb2679481b57d87945df02983f95ff8e6c9ba5928 (diff)
downloadframeworks_base-2b6c32ca4177f1a97307f9cbd81ca485df28762c.zip
frameworks_base-2b6c32ca4177f1a97307f9cbd81ca485df28762c.tar.gz
frameworks_base-2b6c32ca4177f1a97307f9cbd81ca485df28762c.tar.bz2
Fix spurious ANRs in native activities.
Some native activities experienced ANRs when the input consumer deferred an input event due to client-side batching. If the input channel was fully emptied then the client had no way of knowing that it should wake up to handle the deferred input event. This patch also fixes some lock issues in the native activity input queue implementation. In at least one error case, it was possible for a function to exit without releasing the lock. Bug: 6051176 Change-Id: I4d9d843237e69b9834f8d8b360031b677fcab8c3
Diffstat (limited to 'include')
-rw-r--r--include/android_runtime/android_app_NativeActivity.h13
-rw-r--r--include/androidfw/Input.h20
-rw-r--r--include/androidfw/InputTransport.h24
3 files changed, 47 insertions, 10 deletions
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index a59677a..7977c23 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -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;
diff --git a/include/androidfw/Input.h b/include/androidfw/Input.h
index f5db6e2..a4ebd95 100644
--- a/include/androidfw/Input.h
+++ b/include/androidfw/Input.h
@@ -616,6 +616,26 @@ private:
};
/*
+ * 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.
*/
class VelocityTracker {
diff --git a/include/androidfw/InputTransport.h b/include/androidfw/InputTransport.h
index a846e65..29c296e 100644
--- a/include/androidfw/InputTransport.h
+++ b/include/androidfw/InputTransport.h
@@ -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: