Input dispatcher ANR handling enhancements.

This change is essentially a rewrite of the main input dispatcher loop
with the target identification folded in.  Since the input dispatcher now
has all of the window state, it can make better decisions about
when to ANR.

Added a .5 second deadline for processing app switch keys.  This behavior
predates Gingerbread but had not previously been ported.

Fixed some timing inaccuracies in the ANR accounting that could cause
applications to ANR sooner than they should have.

Added a mechanism for tracking key and motion events that have been
dispatched to a window so that appropriate cancelation events can be
synthesized when recovering from ANR.  This change helps to keep
applications in sync so they don't end up with stuck buttons upon
recovery from ANRs.

Added more comments to describe the tricky parts of PollLoop.

Change-Id: I13dffca27acb436fc383980db536abc4d8b9e6f1
This commit is contained in:
Jeff Brown 2010-09-08 11:49:43 -07:00
parent f76fc380f5
commit a665ca805c
9 changed files with 2434 additions and 698 deletions

View File

@ -30,6 +30,7 @@
#include <stddef.h>
#include <unistd.h>
#include <limits.h>
namespace android {
@ -108,15 +109,134 @@ struct InputTarget {
// Flags for the input target.
int32_t flags;
// The timeout for event delivery to this target in nanoseconds. Or -1 if none.
// The timeout for event delivery to this target in nanoseconds, or -1 to wait indefinitely.
nsecs_t timeout;
// The time already spent waiting for this target in nanoseconds, or 0 if none.
nsecs_t timeSpentWaitingForApplication;
// The x and y offset to add to a MotionEvent as it is delivered.
// (ignored for KeyEvents)
float xOffset, yOffset;
};
/*
* An input window describes the bounds of a window that can receive input.
*/
struct InputWindow {
// Window flags from WindowManager.LayoutParams
enum {
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
FLAG_DIM_BEHIND = 0x00000002,
FLAG_BLUR_BEHIND = 0x00000004,
FLAG_NOT_FOCUSABLE = 0x00000008,
FLAG_NOT_TOUCHABLE = 0x00000010,
FLAG_NOT_TOUCH_MODAL = 0x00000020,
FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040,
FLAG_KEEP_SCREEN_ON = 0x00000080,
FLAG_LAYOUT_IN_SCREEN = 0x00000100,
FLAG_LAYOUT_NO_LIMITS = 0x00000200,
FLAG_FULLSCREEN = 0x00000400,
FLAG_FORCE_NOT_FULLSCREEN = 0x00000800,
FLAG_DITHER = 0x00001000,
FLAG_SECURE = 0x00002000,
FLAG_SCALED = 0x00004000,
FLAG_IGNORE_CHEEK_PRESSES = 0x00008000,
FLAG_LAYOUT_INSET_DECOR = 0x00010000,
FLAG_ALT_FOCUSABLE_IM = 0x00020000,
FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000,
FLAG_SHOW_WHEN_LOCKED = 0x00080000,
FLAG_SHOW_WALLPAPER = 0x00100000,
FLAG_TURN_SCREEN_ON = 0x00200000,
FLAG_DISMISS_KEYGUARD = 0x00400000,
FLAG_IMMERSIVE = 0x00800000,
FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000,
FLAG_COMPATIBLE_WINDOW = 0x20000000,
FLAG_SYSTEM_ERROR = 0x40000000,
};
// Window types from WindowManager.LayoutParams
enum {
FIRST_APPLICATION_WINDOW = 1,
TYPE_BASE_APPLICATION = 1,
TYPE_APPLICATION = 2,
TYPE_APPLICATION_STARTING = 3,
LAST_APPLICATION_WINDOW = 99,
FIRST_SUB_WINDOW = 1000,
TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW,
TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1,
TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2,
TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3,
TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4,
LAST_SUB_WINDOW = 1999,
FIRST_SYSTEM_WINDOW = 2000,
TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW,
TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1,
TYPE_PHONE = FIRST_SYSTEM_WINDOW+2,
TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3,
TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4,
TYPE_TOAST = FIRST_SYSTEM_WINDOW+5,
TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6,
TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7,
TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8,
TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9,
TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10,
TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11,
TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13,
TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14,
LAST_SYSTEM_WINDOW = 2999,
};
sp<InputChannel> inputChannel;
int32_t layoutParamsFlags;
int32_t layoutParamsType;
nsecs_t dispatchingTimeout;
int32_t frameLeft;
int32_t frameTop;
int32_t frameRight;
int32_t frameBottom;
int32_t visibleFrameLeft;
int32_t visibleFrameTop;
int32_t visibleFrameRight;
int32_t visibleFrameBottom;
int32_t touchableAreaLeft;
int32_t touchableAreaTop;
int32_t touchableAreaRight;
int32_t touchableAreaBottom;
bool visible;
bool hasFocus;
bool hasWallpaper;
bool paused;
int32_t ownerPid;
int32_t ownerUid;
bool visibleFrameIntersects(const InputWindow* other) const;
bool touchableAreaContainsPoint(int32_t x, int32_t y) const;
};
/*
* A private handle type used by the input manager to track the window.
*/
class InputApplicationHandle : public RefBase {
protected:
InputApplicationHandle() { }
virtual ~InputApplicationHandle() { }
};
/*
* An input application describes properties of an application that can receive input.
*/
struct InputApplication {
String8 name;
nsecs_t dispatchingTimeout;
sp<InputApplicationHandle> handle;
};
/*
* Input dispatcher policy interface.
*
@ -135,14 +255,16 @@ public:
/* Notifies the system that a configuration change has occurred. */
virtual void notifyConfigurationChanged(nsecs_t when) = 0;
/* Notifies the system that an application is not responding.
* Returns a new timeout to continue waiting, or 0 to abort dispatch. */
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0;
/* Notifies the system that an input channel is not responding.
* Returns true and a new timeout value if the dispatcher should keep waiting.
* Otherwise returns false. */
virtual bool notifyInputChannelANR(const sp<InputChannel>& inputChannel,
nsecs_t& outNewTimeout) = 0;
* Returns a new timeout to continue waiting, or 0 to abort dispatch. */
virtual nsecs_t notifyInputChannelANR(const sp<InputChannel>& inputChannel) = 0;
/* Notifies the system that an input channel recovered from ANR. */
virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) = 0;
@ -153,29 +275,27 @@ public:
/* Gets the key repeat inter-key delay. */
virtual nsecs_t getKeyRepeatDelay() = 0;
/* Waits for key event input targets to become available.
* If the event is being injected, injectorPid and injectorUid should specify the
* process id and used id of the injecting application, otherwise they should both
* be -1.
* Returns one of the INPUT_EVENT_INJECTION_XXX constants. */
virtual int32_t waitForKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
int32_t injectorPid, int32_t injectorUid,
Vector<InputTarget>& outTargets) = 0;
/* Waits for motion event targets to become available.
* If the event is being injected, injectorPid and injectorUid should specify the
* process id and used id of the injecting application, otherwise they should both
* be -1.
* Returns one of the INPUT_EVENT_INJECTION_XXX constants. */
virtual int32_t waitForMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
int32_t injectorPid, int32_t injectorUid,
Vector<InputTarget>& outTargets) = 0;
/* Gets the maximum suggested event delivery rate per second.
* This value is used to throttle motion event movement actions on a per-device
* basis. It is not intended to be a hard limit.
*/
virtual int32_t getMaxEventsPerSecond() = 0;
/* Allows the policy a chance to intercept a key before dispatching. */
virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
/* Poke user activity for an event dispatched to a window. */
virtual void pokeUserActivity(nsecs_t eventTime, int32_t windowType, int32_t eventType) = 0;
/* Checks whether a given application pid/uid has permission to inject input events
* into other applications.
*
* This method is special in that its implementation promises to be non-reentrant and
* is safe to call while holding other locks. (Most other methods make no such guarantees!)
*/
virtual bool checkInjectEventsPermissionNonReentrant(
int32_t injectorPid, int32_t injectorUid) = 0;
};
@ -187,6 +307,11 @@ protected:
virtual ~InputDispatcherInterface() { }
public:
/* Dumps the state of the input dispatcher.
*
* This method may be called on any thread (usually by the input manager). */
virtual void dump(String8& dump) = 0;
/* Runs a single iteration of the dispatch loop.
* Nominally processes one queued event, a timeout, or a response from an input consumer.
*
@ -199,7 +324,6 @@ public:
* These methods should only be called on the input reader thread.
*/
virtual void notifyConfigurationChanged(nsecs_t eventTime) = 0;
virtual void notifyAppSwitchComing(nsecs_t eventTime) = 0;
virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
@ -219,6 +343,24 @@ public:
virtual int32_t injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) = 0;
/* Sets the list of input windows.
*
* This method may be called on any thread (usually by the input manager).
*/
virtual void setInputWindows(const Vector<InputWindow>& inputWindows) = 0;
/* Sets the focused application.
*
* This method may be called on any thread (usually by the input manager).
*/
virtual void setFocusedApplication(const InputApplication* inputApplication) = 0;
/* Sets the input dispatching mode.
*
* This method may be called on any thread (usually by the input manager).
*/
virtual void setInputDispatchMode(bool enabled, bool frozen) = 0;
/* Preempts input dispatch in progress by making pending synchronous
* dispatches asynchronous instead. This method is generally called during a focus
* transition from one application to the next so as to enable the new application
@ -230,10 +372,11 @@ public:
virtual void preemptInputDispatch() = 0;
/* Registers or unregister input channels that may be used as targets for input events.
* If monitor is true, the channel will receive a copy of all input events.
*
* These methods may be called on any thread (usually by the input manager).
*/
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) = 0;
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) = 0;
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
};
@ -261,10 +404,11 @@ protected:
public:
explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
virtual void dump(String8& dump);
virtual void dispatchOnce();
virtual void notifyConfigurationChanged(nsecs_t eventTime);
virtual void notifyAppSwitchComing(nsecs_t eventTime);
virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, nsecs_t downTime);
@ -277,9 +421,12 @@ public:
virtual int32_t injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis);
virtual void setInputWindows(const Vector<InputWindow>& inputWindows);
virtual void setFocusedApplication(const InputApplication* inputApplication);
virtual void setInputDispatchMode(bool enabled, bool frozen);
virtual void preemptInputDispatch();
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel);
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor);
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
private:
@ -310,6 +457,8 @@ private:
int32_t pendingSyncDispatches; // the number of synchronous dispatches in progress
inline bool isInjected() { return injectorPid >= 0; }
void recycle();
};
struct ConfigurationChangedEntry : EventEntry {
@ -326,6 +475,17 @@ private:
int32_t metaState;
int32_t repeatCount;
nsecs_t downTime;
bool syntheticRepeat; // set to true for synthetic key repeats
enum InterceptKeyResult {
INTERCEPT_KEY_RESULT_UNKNOWN,
INTERCEPT_KEY_RESULT_SKIP,
INTERCEPT_KEY_RESULT_CONTINUE,
};
InterceptKeyResult interceptKeyResult; // set based on the interception result
void recycle();
};
struct MotionSample {
@ -380,9 +540,13 @@ private:
// will be set to NULL.
MotionSample* tailMotionSample;
inline bool isSyncTarget() {
inline bool isSyncTarget() const {
return targetFlags & InputTarget::FLAG_SYNC;
}
inline void preemptSyncTarget() {
targetFlags &= ~ InputTarget::FLAG_SYNC;
}
};
// A command entry captures state and behavior for an action to be performed in the
@ -413,37 +577,43 @@ private:
// parameters for the command (usage varies by command)
sp<Connection> connection;
nsecs_t eventTime;
KeyEntry* keyEntry;
sp<InputChannel> inputChannel;
sp<InputApplicationHandle> inputApplicationHandle;
int32_t windowType;
int32_t userActivityEventType;
};
// Generic queue implementation.
template <typename T>
struct Queue {
T head;
T tail;
T headSentinel;
T tailSentinel;
inline Queue() {
head.prev = NULL;
head.next = & tail;
tail.prev = & head;
tail.next = NULL;
headSentinel.prev = NULL;
headSentinel.next = & tailSentinel;
tailSentinel.prev = & headSentinel;
tailSentinel.next = NULL;
}
inline bool isEmpty() {
return head.next == & tail;
inline bool isEmpty() const {
return headSentinel.next == & tailSentinel;
}
inline void enqueueAtTail(T* entry) {
T* last = tail.prev;
T* last = tailSentinel.prev;
last->next = entry;
entry->prev = last;
entry->next = & tail;
tail.prev = entry;
entry->next = & tailSentinel;
tailSentinel.prev = entry;
}
inline void enqueueAtHead(T* entry) {
T* first = head.next;
head.next = entry;
entry->prev = & head;
T* first = headSentinel.next;
headSentinel.next = entry;
entry->prev = & headSentinel;
entry->next = first;
first->prev = entry;
}
@ -454,7 +624,7 @@ private:
}
inline T* dequeueAtHead() {
T* first = head.next;
T* first = headSentinel.next;
dequeue(first);
return first;
}
@ -476,7 +646,8 @@ private:
float xPrecision, float yPrecision,
nsecs_t downTime, uint32_t pointerCount,
const int32_t* pointerIds, const PointerCoords* pointerCoords);
DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry);
DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry,
int32_t targetFlags, float xOffset, float yOffset, nsecs_t timeout);
CommandEntry* obtainCommandEntry(Command command);
void releaseEventEntry(EventEntry* entry);
@ -500,6 +671,85 @@ private:
void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime);
};
/* Tracks dispatched key and motion event state so that cancelation events can be
* synthesized when events are dropped. */
class InputState {
public:
// Specifies whether a given event will violate input state consistency.
enum Consistency {
// The event is consistent with the current input state.
CONSISTENT,
// The event is inconsistent with the current input state but applications
// will tolerate it. eg. Down followed by another down.
TOLERABLE,
// The event is inconsistent with the current input state and will probably
// cause applications to crash. eg. Up without prior down, move with
// unexpected number of pointers.
BROKEN
};
InputState();
~InputState();
// Returns true if there is no state to be canceled.
bool isNeutral() const;
// Returns true if the input state believes it is out of sync.
bool isOutOfSync() const;
// Sets the input state to be out of sync if it is not neutral.
void setOutOfSync();
// Resets the input state out of sync flag.
void resetOutOfSync();
// Records tracking information for an event that has just been published.
// Returns whether the event is consistent with the current input state.
Consistency trackEvent(const EventEntry* entry);
// Records tracking information for a key event that has just been published.
// Returns whether the event is consistent with the current input state.
Consistency trackKey(const KeyEntry* entry);
// Records tracking information for a motion event that has just been published.
// Returns whether the event is consistent with the current input state.
Consistency trackMotion(const MotionEntry* entry);
// Synthesizes cancelation events for the current state.
void synthesizeCancelationEvents(Allocator* allocator,
Vector<EventEntry*>& outEvents) const;
// Clears the current state.
void clear();
private:
bool mIsOutOfSync;
struct KeyMemento {
int32_t deviceId;
int32_t source;
int32_t keyCode;
int32_t scanCode;
nsecs_t downTime;
};
struct MotionMemento {
int32_t deviceId;
int32_t source;
float xPrecision;
float yPrecision;
nsecs_t downTime;
uint32_t pointerCount;
int32_t pointerIds[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
void setPointers(const MotionEntry* entry);
};
Vector<KeyMemento> mKeyMementos;
Vector<MotionMemento> mMotionMementos;
};
/* Manages the dispatch state associated with a single input channel. */
class Connection : public RefBase {
protected:
@ -520,6 +770,7 @@ private:
Status status;
sp<InputChannel> inputChannel;
InputPublisher inputPublisher;
InputState inputState;
Queue<DispatchEntry> outboundQueue;
nsecs_t nextTimeoutTime; // next timeout time (LONG_LONG_MAX if none)
@ -540,28 +791,34 @@ private:
// Determine whether this connection has a pending synchronous dispatch target.
// Since there can only ever be at most one such target at a time, if there is one,
// it must be at the tail because nothing else can be enqueued after it.
inline bool hasPendingSyncTarget() {
return ! outboundQueue.isEmpty() && outboundQueue.tail.prev->isSyncTarget();
inline bool hasPendingSyncTarget() const {
return ! outboundQueue.isEmpty() && outboundQueue.tailSentinel.prev->isSyncTarget();
}
// Assuming there is a pending sync target, make it async.
inline void preemptSyncTarget() {
outboundQueue.tailSentinel.prev->preemptSyncTarget();
}
// Gets the time since the current event was originally obtained from the input driver.
inline double getEventLatencyMillis(nsecs_t currentTime) {
inline double getEventLatencyMillis(nsecs_t currentTime) const {
return (currentTime - lastEventTime) / 1000000.0;
}
// Gets the time since the current event entered the outbound dispatch queue.
inline double getDispatchLatencyMillis(nsecs_t currentTime) {
inline double getDispatchLatencyMillis(nsecs_t currentTime) const {
return (currentTime - lastDispatchTime) / 1000000.0;
}
// Gets the time since the current event ANR was declared, if applicable.
inline double getANRLatencyMillis(nsecs_t currentTime) {
inline double getANRLatencyMillis(nsecs_t currentTime) const {
return (currentTime - lastANRTime) / 1000000.0;
}
status_t initialize();
void setNextTimeoutTime(nsecs_t currentTime, nsecs_t timeout);
void resetTimeout(nsecs_t currentTime);
};
sp<InputDispatcherPolicyInterface> mPolicy;
@ -571,9 +828,26 @@ private:
Allocator mAllocator;
sp<PollLoop> mPollLoop;
EventEntry* mPendingEvent;
Queue<EventEntry> mInboundQueue;
Queue<CommandEntry> mCommandQueue;
Vector<EventEntry*> mTempCancelationEvents;
void dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, nsecs_t keyRepeatDelay,
nsecs_t* nextWakeupTime);
// Enqueues an inbound event. Returns true if mPollLoop->wake() should be called.
bool enqueueInboundEventLocked(EventEntry* entry);
// App switch latency optimization.
nsecs_t mAppSwitchDueTime;
static bool isAppSwitchKey(int32_t keyCode);
bool isAppSwitchPendingLocked();
bool detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry);
void resetPendingAppSwitchLocked(bool handled);
// All registered connections mapped by receive pipe file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
@ -591,20 +865,15 @@ private:
// the duration.
Vector<Connection*> mTimedOutConnections;
// Preallocated key and motion event objects used only to ask the input dispatcher policy
// for the targets of an event that is to be dispatched.
KeyEvent mReusableKeyEvent;
MotionEvent mReusableMotionEvent;
// Input channels that will receive a copy of all input events.
Vector<sp<InputChannel> > mMonitoringChannels;
// The input targets that were most recently identified for dispatch.
// If there is a synchronous event dispatch in progress, the current input targets will
// remain unchanged until the dispatch has completed or been aborted.
Vector<InputTarget> mCurrentInputTargets;
bool mCurrentInputTargetsValid; // false while targets are being recomputed
// Preallocated key event object used for policy inquiries.
KeyEvent mReusableKeyEvent;
// Event injection and synchronization.
Condition mInjectionResultAvailableCondition;
EventEntry* createEntryFromInputEventLocked(const InputEvent* event);
EventEntry* createEntryFromInjectedInputEventLocked(const InputEvent* event);
void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
Condition mInjectionSyncFinishedCondition;
@ -622,36 +891,108 @@ private:
} mThrottleState;
// Key repeat tracking.
// XXX Move this up to the input reader instead.
struct KeyRepeatState {
KeyEntry* lastKeyEntry; // or null if no repeat
nsecs_t nextRepeatTime;
} mKeyRepeatState;
void resetKeyRepeatLocked();
KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime, nsecs_t keyRepeatTimeout);
// Deferred command processing.
bool runCommandsLockedInterruptible();
CommandEntry* postCommandLocked(Command command);
// Process events that have just been dequeued from the head of the input queue.
void processConfigurationChangedLockedInterruptible(
nsecs_t currentTime, ConfigurationChangedEntry* entry);
void processKeyLockedInterruptible(
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout);
void processKeyRepeatLockedInterruptible(
nsecs_t currentTime, nsecs_t keyRepeatTimeout);
void processMotionLockedInterruptible(
nsecs_t currentTime, MotionEntry* entry);
// Inbound event processing.
void drainInboundQueueLocked();
void releasePendingEventLocked(bool wasDropped);
void releaseInboundEventLocked(EventEntry* entry, bool wasDropped);
bool isEventFromReliableSourceLocked(EventEntry* entry);
// Identify input targets for an event and dispatch to them.
void identifyInputTargetsAndDispatchKeyLockedInterruptible(
nsecs_t currentTime, KeyEntry* entry);
void identifyInputTargetsAndDispatchMotionLockedInterruptible(
nsecs_t currentTime, MotionEntry* entry);
// Dispatch state.
bool mDispatchEnabled;
bool mDispatchFrozen;
Vector<InputWindow> mWindows;
Vector<InputWindow*> mWallpaperWindows;
// Focus tracking for keys, trackball, etc.
InputWindow* mFocusedWindow;
// Focus tracking for touch.
bool mTouchDown;
InputWindow* mTouchedWindow; // primary target for current down
bool mTouchedWindowIsObscured; // true if other windows may obscure the target
Vector<InputWindow*> mTouchedWallpaperWindows; // wallpaper targets
struct OutsideTarget {
InputWindow* window;
bool obscured;
};
Vector<OutsideTarget> mTempTouchedOutsideTargets; // temporary outside touch targets
Vector<sp<InputChannel> > mTempTouchedWallpaperChannels; // temporary wallpaper targets
// Focused application.
InputApplication* mFocusedApplication;
InputApplication mFocusedApplicationStorage; // preallocated storage for mFocusedApplication
void releaseFocusedApplicationLocked();
// Dispatch inbound events.
bool dispatchConfigurationChangedLocked(
nsecs_t currentTime, ConfigurationChangedEntry* entry);
bool dispatchKeyLocked(
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
nsecs_t* nextWakeupTime);
bool dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry,
nsecs_t* nextWakeupTime);
void dispatchEventToCurrentInputTargetsLocked(
nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry);
void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry);
// The input targets that were most recently identified for dispatch.
// If there is a synchronous event dispatch in progress, the current input targets will
// remain unchanged until the dispatch has completed or been aborted.
bool mCurrentInputTargetsValid; // false while targets are being recomputed
Vector<InputTarget> mCurrentInputTargets;
int32_t mCurrentInputWindowType;
sp<InputChannel> mCurrentInputChannel;
enum InputTargetWaitCause {
INPUT_TARGET_WAIT_CAUSE_NONE,
INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY,
INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY,
};
InputTargetWaitCause mInputTargetWaitCause;
nsecs_t mInputTargetWaitStartTime;
nsecs_t mInputTargetWaitTimeoutTime;
bool mInputTargetWaitTimeoutExpired;
// Finding targets for input events.
void startFindingTargetsLocked();
void finishFindingTargetsLocked(const InputWindow* window);
int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
const InputApplication* application, const InputWindow* window,
nsecs_t* nextWakeupTime);
void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout);
nsecs_t getTimeSpentWaitingForApplicationWhileFindingTargetsLocked(nsecs_t currentTime);
void resetANRTimeoutsLocked();
int32_t findFocusedWindowLocked(nsecs_t currentTime, const EventEntry* entry,
nsecs_t* nextWakeupTime, InputWindow** outWindow);
int32_t findTouchedWindowLocked(nsecs_t currentTime, const MotionEntry* entry,
nsecs_t* nextWakeupTime, InputWindow** outWindow);
void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
nsecs_t timeSpentWaitingForApplication);
void addMonitoringTargetsLocked();
void pokeUserActivityLocked(nsecs_t eventTime, int32_t windowType, int32_t eventType);
bool checkInjectionPermission(const InputWindow* window,
int32_t injectorPid, int32_t injectorUid);
bool isWindowObscuredLocked(const InputWindow* window);
void releaseTouchedWindowLocked();
// Manage the dispatch cycle for a single connection.
// These methods are deliberately not Interruptible because doing all of the work
// with the mutex held makes it easier to ensure that connection invariants are maintained.
@ -659,15 +1000,25 @@ private:
void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
EventEntry* eventEntry, const InputTarget* inputTarget,
bool resumeWithAppendedMotionSample);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
nsecs_t timeSpentWaitingForApplication);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void timeoutDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void resumeAfterTimeoutDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, nsecs_t newTimeout);
void abortDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool broken);
void drainOutboundQueueLocked(Connection* connection, DispatchEntry* firstDispatchEntryToDrain);
static bool handleReceiveCallback(int receiveFd, int events, void* data);
// Preempting input dispatch.
bool preemptInputDispatchInnerLocked();
// Dump state.
void dumpDispatchStateLocked(String8& dump);
void logDispatchStateLocked();
// Add or remove a connection to the mActiveConnections vector.
void activateConnectionLocked(Connection* connection);
void deactivateConnectionLocked(Connection* connection);
@ -683,9 +1034,13 @@ private:
nsecs_t currentTime, const sp<Connection>& connection);
// Outbound policy interactions.
void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry);
void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
void doNotifyInputChannelANRLockedInterruptible(CommandEntry* commandEntry);
void doNotifyInputChannelRecoveredFromANRLockedInterruptible(CommandEntry* commandEntry);
void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry);
void doTargetsNotReadyTimeoutLockedInterruptible(CommandEntry* commandEntry);
};
/* Enqueues and dispatches input events, endlessly. */
@ -702,4 +1057,4 @@ private:
} // namespace android
#endif // _UI_INPUT_DISPATCHER_PRIV_H
#endif // _UI_INPUT_DISPATCHER_H

View File

@ -72,51 +72,11 @@ public:
/* Stops the input manager threads and waits for them to exit. */
virtual status_t stop() = 0;
/* Registers an input channel prior to using it as the target of an event. */
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) = 0;
/* Gets the input reader. */
virtual sp<InputReaderInterface> getReader() = 0;
/* Unregisters an input channel. */
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
/* Injects an input event and optionally waits for sync.
* The synchronization mode determines whether the method blocks while waiting for
* input injection to proceed.
* Returns one of the INPUT_EVENT_INJECTION_XXX constants.
*/
virtual int32_t injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) = 0;
/* Preempts input dispatch in progress by making pending synchronous
* dispatches asynchronous instead. This method is generally called during a focus
* transition from one application to the next so as to enable the new application
* to start receiving input as soon as possible without having to wait for the
* old application to finish up.
*/
virtual void preemptInputDispatch() = 0;
/* Gets input device configuration. */
virtual void getInputConfiguration(InputConfiguration* outConfiguration) = 0;
/* Gets information about the specified input device.
* Returns OK if the device information was obtained or NAME_NOT_FOUND if there
* was no such device.
*/
virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) = 0;
/* Gets the list of all registered device ids. */
virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds) = 0;
/* Queries current input state. */
virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
int32_t scanCode) = 0;
virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
int32_t keyCode) = 0;
virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
int32_t sw) = 0;
/* Determines whether physical keys exist for the given framework-domain key codes. */
virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0;
/* Gets the input dispatcher. */
virtual sp<InputDispatcherInterface> getDispatcher() = 0;
};
class InputManager : public InputManagerInterface {
@ -137,25 +97,8 @@ public:
virtual status_t start();
virtual status_t stop();
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel);
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
virtual int32_t injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis);
virtual void preemptInputDispatch();
virtual void getInputConfiguration(InputConfiguration* outConfiguration);
virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo);
virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds);
virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
int32_t scanCode);
virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
int32_t keyCode);
virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
int32_t sw);
virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags);
virtual sp<InputReaderInterface> getReader();
virtual sp<InputDispatcherInterface> getDispatcher();
private:
sp<InputReaderInterface> mReader;

View File

@ -95,10 +95,6 @@ public:
// The input dispatcher should dispatch the input to the application.
ACTION_DISPATCH = 0x00000001,
// The input dispatcher should perform special filtering in preparation for
// a pending app switch.
ACTION_APP_SWITCH_COMING = 0x00000002,
};
/* Gets information about the display with the specified id.
@ -168,6 +164,11 @@ protected:
virtual ~InputReaderInterface() { }
public:
/* Dumps the state of the input reader.
*
* This method may be called on any thread (usually by the input manager). */
virtual void dump(String8& dump) = 0;
/* Runs a single iteration of the processing loop.
* Nominally reads and processes one incoming message from the EventHub.
*
@ -240,6 +241,8 @@ public:
const sp<InputDispatcherInterface>& dispatcher);
virtual ~InputReader();
virtual void dump(String8& dump);
virtual void loopOnce();
virtual void getInputConfiguration(InputConfiguration* outConfiguration);
@ -305,6 +308,9 @@ private:
GetStateFunc getStateFunc);
bool markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags);
// dump state
void dumpDeviceInfo(String8& dump);
};
@ -759,9 +765,11 @@ protected:
} mLocked;
virtual void configureParameters();
virtual void logParameters();
virtual void configureRawAxes();
virtual void logRawAxes();
virtual bool configureSurfaceLocked();
virtual void logMotionRangesLocked();
virtual void configureVirtualKeysLocked();
virtual void parseCalibration();
virtual void resolveCalibration();

37
include/ui/PowerManager.h Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _UI_POWER_MANAGER_H
#define _UI_POWER_MANAGER_H
namespace android {
enum {
POWER_MANAGER_OTHER_EVENT = 0,
POWER_MANAGER_CHEEK_EVENT = 1,
POWER_MANAGER_TOUCH_EVENT = 2, // touch events are TOUCH for 300ms, and then either
// up events or LONG_TOUCH events.
POWER_MANAGER_LONG_TOUCH_EVENT = 3,
POWER_MANAGER_TOUCH_UP_EVENT = 4,
POWER_MANAGER_BUTTON_EVENT = 5, // Button and trackball events.
POWER_MANAGER_LAST_EVENT = POWER_MANAGER_BUTTON_EVENT, // Last valid event code.
};
} // namespace android
#endif // _UI_POWER_MANAGER_H

View File

@ -172,22 +172,36 @@ private:
void* data;
};
const bool mAllowNonCallbacks;
const bool mAllowNonCallbacks; // immutable
int mWakeReadPipeFd; // immutable
int mWakeWritePipeFd; // immutable
// The lock guards state used to track whether there is a poll() in progress and whether
// there are any other threads waiting in wakeAndLock(). The condition variables
// are used to transfer control among these threads such that all waiters are
// serviced before a new poll can begin.
// The wakeAndLock() method increments mWaiters, wakes the poll, blocks on mAwake
// until mPolling becomes false, then decrements mWaiters again.
// The poll() method blocks on mResume until mWaiters becomes 0, then sets
// mPolling to true, blocks until the poll completes, then resets mPolling to false
// and signals mResume if there are waiters.
Mutex mLock;
bool mPolling;
uint32_t mWaiters;
Condition mAwake;
Condition mResume;
int mWakeReadPipeFd;
int mWakeWritePipeFd;
bool mPolling; // guarded by mLock
uint32_t mWaiters; // guarded by mLock
Condition mAwake; // guarded by mLock
Condition mResume; // guarded by mLock
// The next two vectors are only mutated when mPolling is false since they must
// not be changed while the poll() system call is in progress. To mutate these
// vectors, the poll() must first be awoken then the lock acquired.
Vector<struct pollfd> mRequestedFds;
Vector<RequestedCallback> mRequestedCallbacks;
Vector<PendingCallback> mPendingCallbacks; // used privately by pollOnce
Vector<PendingCallback> mPendingFds; // used privately by pollOnce
// This state is only used privately by pollOnce and does not require a lock since
// it runs on a single thread.
Vector<PendingCallback> mPendingCallbacks;
Vector<PendingCallback> mPendingFds;
size_t mPendingFdsPos;
void openWakePipe();

File diff suppressed because it is too large Load Diff

View File

@ -72,52 +72,12 @@ status_t InputManager::stop() {
return OK;
}
status_t InputManager::registerInputChannel(const sp<InputChannel>& inputChannel) {
return mDispatcher->registerInputChannel(inputChannel);
sp<InputReaderInterface> InputManager::getReader() {
return mReader;
}
status_t InputManager::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
return mDispatcher->unregisterInputChannel(inputChannel);
}
int32_t InputManager::injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) {
return mDispatcher->injectInputEvent(event, injectorPid, injectorUid, syncMode, timeoutMillis);
}
void InputManager::preemptInputDispatch() {
mDispatcher->preemptInputDispatch();
}
void InputManager::getInputConfiguration(InputConfiguration* outConfiguration) {
mReader->getInputConfiguration(outConfiguration);
}
status_t InputManager::getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) {
return mReader->getInputDeviceInfo(deviceId, outDeviceInfo);
}
void InputManager::getInputDeviceIds(Vector<int32_t>& outDeviceIds) {
mReader->getInputDeviceIds(outDeviceIds);
}
int32_t InputManager::getScanCodeState(int32_t deviceId, uint32_t sourceMask,
int32_t scanCode) {
return mReader->getScanCodeState(deviceId, sourceMask, scanCode);
}
int32_t InputManager::getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
int32_t keyCode) {
return mReader->getKeyCodeState(deviceId, sourceMask, keyCode);
}
int32_t InputManager::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) {
return mReader->getSwitchState(deviceId, sourceMask, sw);
}
bool InputManager::hasKeys(int32_t deviceId, uint32_t sourceMask,
size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
return mReader->hasKeys(deviceId, sourceMask, numCodes, keyCodes, outFlags);
sp<InputDispatcherInterface> InputManager::getDispatcher() {
return mDispatcher;
}
} // namespace android

View File

@ -573,6 +573,60 @@ bool InputReader::markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, s
} // release device registy reader lock
}
void InputReader::dump(String8& dump) {
dumpDeviceInfo(dump);
}
static void dumpMotionRange(String8& dump,
const char* name, const InputDeviceInfo::MotionRange* range) {
if (range) {
dump.appendFormat(" %s = { min: %0.3f, max: %0.3f, flat: %0.3f, fuzz: %0.3f }\n",
name, range->min, range->max, range->flat, range->fuzz);
}
}
#define DUMP_MOTION_RANGE(range) \
dumpMotionRange(dump, #range, deviceInfo.getMotionRange(AINPUT_MOTION_RANGE_##range));
void InputReader::dumpDeviceInfo(String8& dump) {
Vector<int32_t> deviceIds;
getInputDeviceIds(deviceIds);
InputDeviceInfo deviceInfo;
for (size_t i = 0; i < deviceIds.size(); i++) {
int32_t deviceId = deviceIds[i];
status_t result = getInputDeviceInfo(deviceId, & deviceInfo);
if (result == NAME_NOT_FOUND) {
continue;
} else if (result != OK) {
dump.appendFormat(" ** Unexpected error %d getting information about input devices.\n",
result);
continue;
}
dump.appendFormat(" Device %d: '%s'\n",
deviceInfo.getId(), deviceInfo.getName().string());
dump.appendFormat(" sources = 0x%08x\n",
deviceInfo.getSources());
dump.appendFormat(" keyboardType = %d\n",
deviceInfo.getKeyboardType());
dump.append(" motion ranges:\n");
DUMP_MOTION_RANGE(X);
DUMP_MOTION_RANGE(Y);
DUMP_MOTION_RANGE(PRESSURE);
DUMP_MOTION_RANGE(SIZE);
DUMP_MOTION_RANGE(TOUCH_MAJOR);
DUMP_MOTION_RANGE(TOUCH_MINOR);
DUMP_MOTION_RANGE(TOOL_MAJOR);
DUMP_MOTION_RANGE(TOOL_MINOR);
DUMP_MOTION_RANGE(ORIENTATION);
}
}
#undef DUMP_MOTION_RANGE
// --- InputReaderThread ---
@ -740,10 +794,6 @@ int32_t InputMapper::getMetaState() {
}
bool InputMapper::applyStandardPolicyActions(nsecs_t when, int32_t policyActions) {
if (policyActions & InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING) {
getDispatcher()->notifyAppSwitchComing(when);
}
return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
}
@ -1249,20 +1299,12 @@ void TouchInputMapper::initializeLocked() {
mLocked.orientedRanges.haveOrientation = false;
}
static void logAxisInfo(RawAbsoluteAxisInfo axis, const char* name) {
if (axis.valid) {
LOGI(INDENT "Raw %s axis: min=%d, max=%d, flat=%d, fuzz=%d",
name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz);
} else {
LOGI(INDENT "Raw %s axis: unknown range", name);
}
}
void TouchInputMapper::configure() {
InputMapper::configure();
// Configure basic parameters.
configureParameters();
logParameters();
// Configure absolute axis information.
configureRawAxes();
@ -1287,6 +1329,18 @@ void TouchInputMapper::configureParameters() {
mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
}
void TouchInputMapper::logParameters() {
if (mParameters.useBadTouchFilter) {
LOGI(INDENT "Bad touch filter enabled.");
}
if (mParameters.useAveragingTouchFilter) {
LOGI(INDENT "Averaging touch filter enabled.");
}
if (mParameters.useJumpyTouchFilter) {
LOGI(INDENT "Jumpy touch filter enabled.");
}
}
void TouchInputMapper::configureRawAxes() {
mRawAxes.x.clear();
mRawAxes.y.clear();
@ -1298,6 +1352,15 @@ void TouchInputMapper::configureRawAxes() {
mRawAxes.orientation.clear();
}
static void logAxisInfo(RawAbsoluteAxisInfo axis, const char* name) {
if (axis.valid) {
LOGI(INDENT "Raw %s axis: min=%d, max=%d, flat=%d, fuzz=%d",
name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz);
} else {
LOGI(INDENT "Raw %s axis: unknown range", name);
}
}
void TouchInputMapper::logRawAxes() {
logAxisInfo(mRawAxes.x, "x");
logAxisInfo(mRawAxes.y, "y");
@ -1331,8 +1394,10 @@ bool TouchInputMapper::configureSurfaceLocked() {
bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
if (sizeChanged) {
LOGI("Device configured: id=0x%x, name=%s (display size was changed)",
LOGI("Device reconfigured (display size changed): id=0x%x, name=%s",
getDeviceId(), getDeviceName().string());
LOGI(INDENT "Width: %dpx", width);
LOGI(INDENT "Height: %dpx", height);
mLocked.surfaceWidth = width;
mLocked.surfaceHeight = height;
@ -1500,9 +1565,41 @@ bool TouchInputMapper::configureSurfaceLocked() {
mLocked.orientedRanges.y.fuzz = orientedYScale;
}
if (sizeChanged) {
logMotionRangesLocked();
}
return true;
}
static void logMotionRangeInfo(InputDeviceInfo::MotionRange* range, const char* name) {
if (range) {
LOGI(INDENT "Output %s range: min=%f, max=%f, flat=%f, fuzz=%f",
name, range->min, range->max, range->flat, range->fuzz);
} else {
LOGI(INDENT "Output %s range: unsupported", name);
}
}
void TouchInputMapper::logMotionRangesLocked() {
logMotionRangeInfo(& mLocked.orientedRanges.x, "x");
logMotionRangeInfo(& mLocked.orientedRanges.y, "y");
logMotionRangeInfo(mLocked.orientedRanges.havePressure
? & mLocked.orientedRanges.pressure : NULL, "pressure");
logMotionRangeInfo(mLocked.orientedRanges.haveSize
? & mLocked.orientedRanges.size : NULL, "size");
logMotionRangeInfo(mLocked.orientedRanges.haveTouchArea
? & mLocked.orientedRanges.touchMajor : NULL, "touchMajor");
logMotionRangeInfo(mLocked.orientedRanges.haveTouchArea
? & mLocked.orientedRanges.touchMinor : NULL, "touchMinor");
logMotionRangeInfo(mLocked.orientedRanges.haveToolArea
? & mLocked.orientedRanges.toolMajor : NULL, "toolMajor");
logMotionRangeInfo(mLocked.orientedRanges.haveToolArea
? & mLocked.orientedRanges.toolMinor : NULL, "toolMinor");
logMotionRangeInfo(mLocked.orientedRanges.haveOrientation
? & mLocked.orientedRanges.orientation : NULL, "orientation");
}
void TouchInputMapper::configureVirtualKeysLocked() {
assert(mRawAxes.x.valid && mRawAxes.y.valid);
@ -1768,16 +1865,18 @@ void TouchInputMapper::resolveCalibration() {
}
void TouchInputMapper::logCalibration() {
LOGI(INDENT "Calibration:");
// Touch Area
switch (mCalibration.touchAreaCalibration) {
case Calibration::TOUCH_AREA_CALIBRATION_NONE:
LOGI(INDENT " touch.touchArea.calibration: none");
LOGI(INDENT INDENT "touch.touchArea.calibration: none");
break;
case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC:
LOGI(INDENT " touch.touchArea.calibration: geometric");
LOGI(INDENT INDENT "touch.touchArea.calibration: geometric");
break;
case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE:
LOGI(INDENT " touch.touchArea.calibration: pressure");
LOGI(INDENT INDENT "touch.touchArea.calibration: pressure");
break;
default:
assert(false);
@ -1786,40 +1885,40 @@ void TouchInputMapper::logCalibration() {
// Tool Area
switch (mCalibration.toolAreaCalibration) {
case Calibration::TOOL_AREA_CALIBRATION_NONE:
LOGI(INDENT " touch.toolArea.calibration: none");
LOGI(INDENT INDENT "touch.toolArea.calibration: none");
break;
case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC:
LOGI(INDENT " touch.toolArea.calibration: geometric");
LOGI(INDENT INDENT "touch.toolArea.calibration: geometric");
break;
case Calibration::TOOL_AREA_CALIBRATION_LINEAR:
LOGI(INDENT " touch.toolArea.calibration: linear");
LOGI(INDENT INDENT "touch.toolArea.calibration: linear");
break;
default:
assert(false);
}
if (mCalibration.haveToolAreaLinearScale) {
LOGI(INDENT " touch.toolArea.linearScale: %f", mCalibration.toolAreaLinearScale);
LOGI(INDENT INDENT "touch.toolArea.linearScale: %f", mCalibration.toolAreaLinearScale);
}
if (mCalibration.haveToolAreaLinearBias) {
LOGI(INDENT " touch.toolArea.linearBias: %f", mCalibration.toolAreaLinearBias);
LOGI(INDENT INDENT "touch.toolArea.linearBias: %f", mCalibration.toolAreaLinearBias);
}
if (mCalibration.haveToolAreaIsSummed) {
LOGI(INDENT " touch.toolArea.isSummed: %d", mCalibration.toolAreaIsSummed);
LOGI(INDENT INDENT "touch.toolArea.isSummed: %d", mCalibration.toolAreaIsSummed);
}
// Pressure
switch (mCalibration.pressureCalibration) {
case Calibration::PRESSURE_CALIBRATION_NONE:
LOGI(INDENT " touch.pressure.calibration: none");
LOGI(INDENT INDENT "touch.pressure.calibration: none");
break;
case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
LOGI(INDENT " touch.pressure.calibration: physical");
LOGI(INDENT INDENT "touch.pressure.calibration: physical");
break;
case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
LOGI(INDENT " touch.pressure.calibration: amplitude");
LOGI(INDENT INDENT "touch.pressure.calibration: amplitude");
break;
default:
assert(false);
@ -1827,10 +1926,10 @@ void TouchInputMapper::logCalibration() {
switch (mCalibration.pressureSource) {
case Calibration::PRESSURE_SOURCE_PRESSURE:
LOGI(INDENT " touch.pressure.source: pressure");
LOGI(INDENT INDENT "touch.pressure.source: pressure");
break;
case Calibration::PRESSURE_SOURCE_TOUCH:
LOGI(INDENT " touch.pressure.source: touch");
LOGI(INDENT INDENT "touch.pressure.source: touch");
break;
case Calibration::PRESSURE_SOURCE_DEFAULT:
break;
@ -1839,16 +1938,16 @@ void TouchInputMapper::logCalibration() {
}
if (mCalibration.havePressureScale) {
LOGI(INDENT " touch.pressure.scale: %f", mCalibration.pressureScale);
LOGI(INDENT INDENT "touch.pressure.scale: %f", mCalibration.pressureScale);
}
// Size
switch (mCalibration.sizeCalibration) {
case Calibration::SIZE_CALIBRATION_NONE:
LOGI(INDENT " touch.size.calibration: none");
LOGI(INDENT INDENT "touch.size.calibration: none");
break;
case Calibration::SIZE_CALIBRATION_NORMALIZED:
LOGI(INDENT " touch.size.calibration: normalized");
LOGI(INDENT INDENT "touch.size.calibration: normalized");
break;
default:
assert(false);
@ -1857,10 +1956,10 @@ void TouchInputMapper::logCalibration() {
// Orientation
switch (mCalibration.orientationCalibration) {
case Calibration::ORIENTATION_CALIBRATION_NONE:
LOGI(INDENT " touch.orientation.calibration: none");
LOGI(INDENT INDENT "touch.orientation.calibration: none");
break;
case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
LOGI(INDENT " touch.orientation.calibration: interpolated");
LOGI(INDENT INDENT "touch.orientation.calibration: interpolated");
break;
default:
assert(false);

View File

@ -119,7 +119,8 @@ int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
if (outData != NULL) *outData = pending.data;
return pending.ident;
}
// Wait for wakeAndLock() waiters to run then set mPolling to true.
mLock.lock();
while (mWaiters != 0) {
mResume.wait(mLock);
@ -127,6 +128,7 @@ int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
mPolling = true;
mLock.unlock();
// Poll.
int32_t result;
size_t requestedCount = mRequestedFds.size();
@ -168,6 +170,7 @@ int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
}
#endif
// Process the poll results.
mPendingCallbacks.clear();
mPendingFds.clear();
mPendingFdsPos = 0;
@ -218,6 +221,7 @@ int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
}
Done:
// Set mPolling to false and wake up the wakeAndLock() waiters.
mLock.lock();
mPolling = false;
if (mWaiters != 0) {
@ -357,11 +361,13 @@ ssize_t PollLoop::getRequestIndexLocked(int fd) {
void PollLoop::wakeAndLock() {
mLock.lock();
mWaiters += 1;
while (mPolling) {
wake();
mAwake.wait(mLock);
}
mWaiters -= 1;
if (mWaiters == 0) {
mResume.signal();