Merge "Make input dispatcher only ANR for foreground windows." into gingerbread
This commit is contained in:
@@ -81,9 +81,8 @@ enum {
|
||||
*/
|
||||
struct InputTarget {
|
||||
enum {
|
||||
/* This flag indicates that subsequent event delivery should be held until the
|
||||
* current event is delivered to this target or a timeout occurs. */
|
||||
FLAG_SYNC = 0x01,
|
||||
/* This flag indicates that the event is being delivered to a foreground application. */
|
||||
FLAG_FOREGROUND = 0x01,
|
||||
|
||||
/* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
|
||||
* of the area of this target and so should instead be delivered as an
|
||||
@@ -109,12 +108,6 @@ struct InputTarget {
|
||||
// Flags for the input target.
|
||||
int32_t flags;
|
||||
|
||||
// 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;
|
||||
@@ -190,6 +183,7 @@ struct InputWindow {
|
||||
};
|
||||
|
||||
sp<InputChannel> inputChannel;
|
||||
String8 name;
|
||||
int32_t layoutParamsFlags;
|
||||
int32_t layoutParamsType;
|
||||
nsecs_t dispatchingTimeout;
|
||||
@@ -206,9 +200,11 @@ struct InputWindow {
|
||||
int32_t touchableAreaRight;
|
||||
int32_t touchableAreaBottom;
|
||||
bool visible;
|
||||
bool canReceiveKeys;
|
||||
bool hasFocus;
|
||||
bool hasWallpaper;
|
||||
bool paused;
|
||||
int32_t layer;
|
||||
int32_t ownerPid;
|
||||
int32_t ownerUid;
|
||||
|
||||
@@ -257,18 +253,12 @@ public:
|
||||
|
||||
/* 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;
|
||||
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
|
||||
const sp<InputChannel>& inputChannel) = 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 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;
|
||||
|
||||
/* Gets the key repeat initial timeout or -1 if automatic key repeating is disabled. */
|
||||
virtual nsecs_t getKeyRepeatTimeout() = 0;
|
||||
|
||||
@@ -361,16 +351,6 @@ public:
|
||||
*/
|
||||
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
|
||||
* to start receiving input as soon as possible without having to wait for the
|
||||
* old application to finish up.
|
||||
*
|
||||
* This method may be called on any thread (usually by the input manager).
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -424,7 +404,6 @@ public:
|
||||
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, bool monitor);
|
||||
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
|
||||
@@ -454,7 +433,7 @@ private:
|
||||
int32_t injectorUid; // -1 if not injected
|
||||
|
||||
bool dispatchInProgress; // initially false, set to true while dispatching
|
||||
int32_t pendingSyncDispatches; // the number of synchronous dispatches in progress
|
||||
int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
|
||||
|
||||
inline bool isInjected() { return injectorPid >= 0; }
|
||||
|
||||
@@ -522,7 +501,6 @@ private:
|
||||
int32_t targetFlags;
|
||||
float xOffset;
|
||||
float yOffset;
|
||||
nsecs_t timeout;
|
||||
|
||||
// True if dispatch has started.
|
||||
bool inProgress;
|
||||
@@ -540,12 +518,8 @@ private:
|
||||
// will be set to NULL.
|
||||
MotionSample* tailMotionSample;
|
||||
|
||||
inline bool isSyncTarget() const {
|
||||
return targetFlags & InputTarget::FLAG_SYNC;
|
||||
}
|
||||
|
||||
inline void preemptSyncTarget() {
|
||||
targetFlags &= ~ InputTarget::FLAG_SYNC;
|
||||
inline bool hasForegroundTarget() const {
|
||||
return targetFlags & InputTarget::FLAG_FOREGROUND;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -628,6 +602,8 @@ private:
|
||||
dequeue(first);
|
||||
return first;
|
||||
}
|
||||
|
||||
uint32_t count() const;
|
||||
};
|
||||
|
||||
/* Allocates queue entries and performs reference counting as needed. */
|
||||
@@ -647,7 +623,7 @@ private:
|
||||
nsecs_t downTime, uint32_t pointerCount,
|
||||
const int32_t* pointerIds, const PointerCoords* pointerCoords);
|
||||
DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry,
|
||||
int32_t targetFlags, float xOffset, float yOffset, nsecs_t timeout);
|
||||
int32_t targetFlags, float xOffset, float yOffset);
|
||||
CommandEntry* obtainCommandEntry(Command command);
|
||||
|
||||
void releaseEventEntry(EventEntry* entry);
|
||||
@@ -761,8 +737,6 @@ private:
|
||||
STATUS_NORMAL,
|
||||
// An unrecoverable communication error has occurred.
|
||||
STATUS_BROKEN,
|
||||
// The client is not responding.
|
||||
STATUS_NOT_RESPONDING,
|
||||
// The input channel has been unregistered.
|
||||
STATUS_ZOMBIE
|
||||
};
|
||||
@@ -772,11 +746,9 @@ private:
|
||||
InputPublisher inputPublisher;
|
||||
InputState inputState;
|
||||
Queue<DispatchEntry> outboundQueue;
|
||||
nsecs_t nextTimeoutTime; // next timeout time (LONG_LONG_MAX if none)
|
||||
|
||||
nsecs_t lastEventTime; // the time when the event was originally captured
|
||||
nsecs_t lastDispatchTime; // the time when the last event was dispatched
|
||||
nsecs_t lastANRTime; // the time when the last ANR was recorded
|
||||
|
||||
explicit Connection(const sp<InputChannel>& inputChannel);
|
||||
|
||||
@@ -788,18 +760,6 @@ private:
|
||||
// Returns NULL if not found.
|
||||
DispatchEntry* findQueuedDispatchEntryForEvent(const EventEntry* eventEntry) const;
|
||||
|
||||
// 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() 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) const {
|
||||
return (currentTime - lastEventTime) / 1000000.0;
|
||||
@@ -810,15 +770,7 @@ private:
|
||||
return (currentTime - lastDispatchTime) / 1000000.0;
|
||||
}
|
||||
|
||||
// Gets the time since the current event ANR was declared, if applicable.
|
||||
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;
|
||||
@@ -851,7 +803,7 @@ private:
|
||||
// All registered connections mapped by receive pipe file descriptor.
|
||||
KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
|
||||
|
||||
ssize_t getConnectionIndex(const sp<InputChannel>& inputChannel);
|
||||
ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
|
||||
|
||||
// Active connections are connections that have a non-empty outbound queue.
|
||||
// We don't use a ref-counted pointer here because we explicitly abort connections
|
||||
@@ -859,12 +811,6 @@ private:
|
||||
// and the connection itself to be deactivated.
|
||||
Vector<Connection*> mActiveConnections;
|
||||
|
||||
// List of connections that have timed out. Only used by dispatchOnce()
|
||||
// We don't use a ref-counted pointer here because it is not possible for a connection
|
||||
// to be unregistered while processing timed out connections since we hold the lock for
|
||||
// the duration.
|
||||
Vector<Connection*> mTimedOutConnections;
|
||||
|
||||
// Input channels that will receive a copy of all input events.
|
||||
Vector<sp<InputChannel> > mMonitoringChannels;
|
||||
|
||||
@@ -877,7 +823,7 @@ private:
|
||||
void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
|
||||
|
||||
Condition mInjectionSyncFinishedCondition;
|
||||
void decrementPendingSyncDispatchesLocked(EventEntry* entry);
|
||||
void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
|
||||
|
||||
// Throttling state.
|
||||
struct ThrottleState {
|
||||
@@ -951,8 +897,6 @@ private:
|
||||
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;
|
||||
@@ -975,8 +919,9 @@ private:
|
||||
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 resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
|
||||
const sp<InputChannel>& inputChannel);
|
||||
nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
|
||||
void resetANRTimeoutsLocked();
|
||||
|
||||
int32_t findFocusedWindowLocked(nsecs_t currentTime, const EventEntry* entry,
|
||||
@@ -984,14 +929,16 @@ private:
|
||||
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 addWindowTargetLocked(const InputWindow* window, int32_t targetFlags);
|
||||
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);
|
||||
bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window);
|
||||
void releaseTouchedWindowLocked();
|
||||
String8 getApplicationWindowLabelLocked(const InputApplication* application,
|
||||
const InputWindow* window);
|
||||
|
||||
// Manage the dispatch cycle for a single connection.
|
||||
// These methods are deliberately not Interruptible because doing all of the work
|
||||
@@ -1000,21 +947,14 @@ 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,
|
||||
nsecs_t timeSpentWaitingForApplication);
|
||||
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
|
||||
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);
|
||||
void drainOutboundQueueLocked(Connection* connection);
|
||||
static int handleReceiveCallback(int receiveFd, int events, void* data);
|
||||
|
||||
// Preempting input dispatch.
|
||||
bool preemptInputDispatchInnerLocked();
|
||||
|
||||
// Dump state.
|
||||
void dumpDispatchStateLocked(String8& dump);
|
||||
void logDispatchStateLocked();
|
||||
@@ -1027,20 +967,23 @@ private:
|
||||
void onDispatchCycleStartedLocked(
|
||||
nsecs_t currentTime, const sp<Connection>& connection);
|
||||
void onDispatchCycleFinishedLocked(
|
||||
nsecs_t currentTime, const sp<Connection>& connection, bool recoveredFromANR);
|
||||
void onDispatchCycleANRLocked(
|
||||
nsecs_t currentTime, const sp<Connection>& connection);
|
||||
void onDispatchCycleBrokenLocked(
|
||||
nsecs_t currentTime, const sp<Connection>& connection);
|
||||
void onANRLocked(
|
||||
nsecs_t currentTime, const InputApplication* application, const InputWindow* window,
|
||||
nsecs_t eventTime, nsecs_t waitStartTime);
|
||||
|
||||
// Outbound policy interactions.
|
||||
void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry);
|
||||
void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
|
||||
void doNotifyInputChannelANRLockedInterruptible(CommandEntry* commandEntry);
|
||||
void doNotifyInputChannelRecoveredFromANRLockedInterruptible(CommandEntry* commandEntry);
|
||||
void doNotifyANRLockedInterruptible(CommandEntry* commandEntry);
|
||||
void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
|
||||
void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry);
|
||||
void doTargetsNotReadyTimeoutLockedInterruptible(CommandEntry* commandEntry);
|
||||
|
||||
// Statistics gathering.
|
||||
void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
|
||||
int32_t injectionResult, nsecs_t timeSpentWaitingForApplication);
|
||||
};
|
||||
|
||||
/* Enqueues and dispatches input events, endlessly. */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,18 +24,13 @@ import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Environment;
|
||||
import android.os.LocalPowerManager;
|
||||
import android.os.PowerManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputDevice;
|
||||
import android.view.InputEvent;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManagerPolicy;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
@@ -83,7 +78,6 @@ public class InputManager {
|
||||
private static native void nativeSetInputWindows(InputWindow[] windows);
|
||||
private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen);
|
||||
private static native void nativeSetFocusedApplication(InputApplication application);
|
||||
private static native void nativePreemptInputDispatch();
|
||||
private static native InputDevice nativeGetInputDevice(int deviceId);
|
||||
private static native int[] nativeGetInputDeviceIds();
|
||||
private static native String nativeDump();
|
||||
@@ -331,10 +325,6 @@ public class InputManager {
|
||||
nativeSetFocusedApplication(application);
|
||||
}
|
||||
|
||||
public void preemptInputDispatch() {
|
||||
nativePreemptInputDispatch();
|
||||
}
|
||||
|
||||
public void setInputDispatchMode(boolean enabled, boolean frozen) {
|
||||
nativeSetInputDispatchMode(enabled, frozen);
|
||||
}
|
||||
@@ -395,20 +385,10 @@ public class InputManager {
|
||||
public void notifyInputChannelBroken(InputChannel inputChannel) {
|
||||
mWindowManagerService.mInputMonitor.notifyInputChannelBroken(inputChannel);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public long notifyInputChannelANR(InputChannel inputChannel) {
|
||||
return mWindowManagerService.mInputMonitor.notifyInputChannelANR(inputChannel);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void notifyInputChannelRecoveredFromANR(InputChannel inputChannel) {
|
||||
mWindowManagerService.mInputMonitor.notifyInputChannelRecoveredFromANR(inputChannel);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public long notifyANR(Object token) {
|
||||
return mWindowManagerService.mInputMonitor.notifyANR(token);
|
||||
public long notifyANR(Object token, InputChannel inputChannel) {
|
||||
return mWindowManagerService.mInputMonitor.notifyANR(token, inputChannel);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
@@ -27,6 +27,9 @@ public final class InputWindow {
|
||||
// The input channel associated with the window.
|
||||
public InputChannel inputChannel;
|
||||
|
||||
// The window name.
|
||||
public String name;
|
||||
|
||||
// Window layout params attributes. (WindowManager.LayoutParams)
|
||||
public int layoutParamsFlags;
|
||||
public int layoutParamsType;
|
||||
@@ -55,6 +58,9 @@ public final class InputWindow {
|
||||
// Window is visible.
|
||||
public boolean visible;
|
||||
|
||||
// Window can receive keys.
|
||||
public boolean canReceiveKeys;
|
||||
|
||||
// Window has focus.
|
||||
public boolean hasFocus;
|
||||
|
||||
@@ -64,6 +70,9 @@ public final class InputWindow {
|
||||
// Input event dispatching is paused.
|
||||
public boolean paused;
|
||||
|
||||
// Window layer.
|
||||
public int layer;
|
||||
|
||||
// Id of process and user that owns the window.
|
||||
public int ownerPid;
|
||||
public int ownerUid;
|
||||
|
||||
@@ -5096,61 +5096,39 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/* Notifies the window manager about an input channel that is not responding.
|
||||
/* Notifies the window manager about an application that is not responding.
|
||||
* Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
|
||||
*
|
||||
* Called by the InputManager.
|
||||
*/
|
||||
public long notifyInputChannelANR(InputChannel inputChannel) {
|
||||
AppWindowToken token;
|
||||
synchronized (mWindowMap) {
|
||||
WindowState windowState = getWindowStateForInputChannelLocked(inputChannel);
|
||||
if (windowState == null) {
|
||||
return 0; // window is unknown, abort dispatching
|
||||
public long notifyANR(Object token, InputChannel inputChannel) {
|
||||
AppWindowToken appWindowToken = null;
|
||||
if (inputChannel != null) {
|
||||
synchronized (mWindowMap) {
|
||||
WindowState windowState = getWindowStateForInputChannelLocked(inputChannel);
|
||||
if (windowState != null) {
|
||||
Slog.i(TAG, "Input event dispatching timed out sending to "
|
||||
+ windowState.mAttrs.getTitle());
|
||||
appWindowToken = windowState.mAppToken;
|
||||
}
|
||||
}
|
||||
|
||||
Slog.i(TAG, "Input event dispatching timed out sending to "
|
||||
+ windowState.mAttrs.getTitle());
|
||||
token = windowState.mAppToken;
|
||||
}
|
||||
|
||||
return notifyANRInternal(token);
|
||||
}
|
||||
|
||||
/* Notifies the window manager about an input channel spontaneously recovering from ANR
|
||||
* by successfully delivering the event that originally timed out.
|
||||
*
|
||||
* Called by the InputManager.
|
||||
*/
|
||||
public void notifyInputChannelRecoveredFromANR(InputChannel inputChannel) {
|
||||
// Nothing to do just now.
|
||||
// Just wait for the user to dismiss the ANR dialog.
|
||||
}
|
||||
|
||||
/* Notifies the window manager about an application that is not responding
|
||||
* in general rather than with respect to a particular input channel.
|
||||
* Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
|
||||
*
|
||||
* Called by the InputManager.
|
||||
*/
|
||||
public long notifyANR(Object token) {
|
||||
AppWindowToken appWindowToken = (AppWindowToken) token;
|
||||
if (appWindowToken == null && token != null) {
|
||||
appWindowToken = (AppWindowToken) token;
|
||||
Slog.i(TAG, "Input event dispatching timed out sending to application "
|
||||
+ appWindowToken.stringName);
|
||||
}
|
||||
|
||||
Slog.i(TAG, "Input event dispatching timed out sending to application "
|
||||
+ appWindowToken.stringName);
|
||||
return notifyANRInternal(appWindowToken);
|
||||
}
|
||||
|
||||
private long notifyANRInternal(AppWindowToken token) {
|
||||
if (token != null && token.appToken != null) {
|
||||
if (appWindowToken != null && appWindowToken.appToken != null) {
|
||||
try {
|
||||
// Notify the activity manager about the timeout and let it decide whether
|
||||
// to abort dispatching or keep waiting.
|
||||
boolean abort = token.appToken.keyDispatchingTimedOut();
|
||||
boolean abort = appWindowToken.appToken.keyDispatchingTimedOut();
|
||||
if (! abort) {
|
||||
// The activity manager declined to abort dispatching.
|
||||
// Wait a bit longer and timeout again later.
|
||||
return token.inputDispatchingTimeoutNanos;
|
||||
return appWindowToken.inputDispatchingTimeoutNanos;
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
}
|
||||
@@ -5203,13 +5181,16 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
// Add a window to our list of input windows.
|
||||
final InputWindow inputWindow = mTempInputWindows.add();
|
||||
inputWindow.inputChannel = child.mInputChannel;
|
||||
inputWindow.name = child.toString();
|
||||
inputWindow.layoutParamsFlags = flags;
|
||||
inputWindow.layoutParamsType = type;
|
||||
inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
|
||||
inputWindow.visible = isVisible;
|
||||
inputWindow.canReceiveKeys = child.canReceiveKeys();
|
||||
inputWindow.hasFocus = hasFocus;
|
||||
inputWindow.hasWallpaper = hasWallpaper;
|
||||
inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false;
|
||||
inputWindow.layer = child.mLayer;
|
||||
inputWindow.ownerPid = child.mSession.mPid;
|
||||
inputWindow.ownerUid = child.mSession.mUid;
|
||||
|
||||
@@ -5302,23 +5283,6 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
if (newWindow != mInputFocus) {
|
||||
if (newWindow != null && newWindow.canReceiveKeys()) {
|
||||
// If the new input focus is an error window or appears above the current
|
||||
// input focus, preempt any pending synchronous dispatch so that we can
|
||||
// start delivering events to the new input focus as soon as possible.
|
||||
if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
|
||||
if (DEBUG_INPUT) {
|
||||
Slog.v(TAG, "New SYSTEM_ERROR window; resetting state");
|
||||
}
|
||||
preemptInputDispatchLw();
|
||||
} else if (mInputFocus != null && newWindow.mLayer > mInputFocus.mLayer) {
|
||||
if (DEBUG_INPUT) {
|
||||
Slog.v(TAG, "Transferring focus to new window at higher layer: "
|
||||
+ "old win layer=" + mInputFocus.mLayer
|
||||
+ ", new win layer=" + newWindow.mLayer);
|
||||
}
|
||||
preemptInputDispatchLw();
|
||||
}
|
||||
|
||||
// Displaying a window implicitly causes dispatching to be unpaused.
|
||||
// This is to protect against bugs if someone pauses dispatching but
|
||||
// forgets to resume.
|
||||
@@ -5330,14 +5294,6 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/* Tells the dispatcher to stop waiting for its current synchronous event targets.
|
||||
* Essentially, just makes those dispatches asynchronous so a new dispatch cycle
|
||||
* can begin.
|
||||
*/
|
||||
private void preemptInputDispatchLw() {
|
||||
mInputManager.preemptInputDispatch();
|
||||
}
|
||||
|
||||
public void setFocusedAppLw(AppWindowToken newApp) {
|
||||
// Focused app has changed.
|
||||
if (newApp == null) {
|
||||
|
||||
@@ -49,8 +49,6 @@ static struct {
|
||||
jmethodID notifyConfigurationChanged;
|
||||
jmethodID notifyLidSwitchChanged;
|
||||
jmethodID notifyInputChannelBroken;
|
||||
jmethodID notifyInputChannelANR;
|
||||
jmethodID notifyInputChannelRecoveredFromANR;
|
||||
jmethodID notifyANR;
|
||||
jmethodID virtualKeyDownFeedback;
|
||||
jmethodID interceptKeyBeforeQueueing;
|
||||
@@ -85,6 +83,7 @@ static struct {
|
||||
jclass clazz;
|
||||
|
||||
jfieldID inputChannel;
|
||||
jfieldID name;
|
||||
jfieldID layoutParamsFlags;
|
||||
jfieldID layoutParamsType;
|
||||
jfieldID dispatchingTimeoutNanos;
|
||||
@@ -101,9 +100,11 @@ static struct {
|
||||
jfieldID touchableAreaRight;
|
||||
jfieldID touchableAreaBottom;
|
||||
jfieldID visible;
|
||||
jfieldID canReceiveKeys;
|
||||
jfieldID hasFocus;
|
||||
jfieldID hasWallpaper;
|
||||
jfieldID paused;
|
||||
jfieldID layer;
|
||||
jfieldID ownerPid;
|
||||
jfieldID ownerUid;
|
||||
} gInputWindowClassInfo;
|
||||
@@ -168,7 +169,6 @@ public:
|
||||
void setInputWindows(JNIEnv* env, jobjectArray windowObjArray);
|
||||
void setFocusedApplication(JNIEnv* env, jobject applicationObj);
|
||||
void setInputDispatchMode(bool enabled, bool frozen);
|
||||
void preemptInputDispatch();
|
||||
|
||||
/* --- InputReaderPolicyInterface implementation --- */
|
||||
|
||||
@@ -191,10 +191,9 @@ public:
|
||||
/* --- InputDispatcherPolicyInterface implementation --- */
|
||||
|
||||
virtual void notifyConfigurationChanged(nsecs_t when);
|
||||
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle);
|
||||
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
|
||||
const sp<InputChannel>& inputChannel);
|
||||
virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel);
|
||||
virtual nsecs_t notifyInputChannelANR(const sp<InputChannel>& inputChannel);
|
||||
virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel);
|
||||
virtual nsecs_t getKeyRepeatTimeout();
|
||||
virtual nsecs_t getKeyRepeatDelay();
|
||||
virtual int32_t getMaxEventsPerSecond();
|
||||
@@ -702,32 +701,40 @@ void NativeInputManager::notifyConfigurationChanged(nsecs_t when) {
|
||||
checkAndClearExceptionFromCallback(env, "notifyConfigurationChanged");
|
||||
}
|
||||
|
||||
nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle) {
|
||||
nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
|
||||
const sp<InputChannel>& inputChannel) {
|
||||
#if DEBUG_INPUT_DISPATCHER_POLICY
|
||||
LOGD("notifyANR");
|
||||
#endif
|
||||
|
||||
JNIEnv* env = jniEnv();
|
||||
|
||||
ApplicationToken* token = static_cast<ApplicationToken*>(inputApplicationHandle.get());
|
||||
jweak tokenObjWeak = token->getTokenObj();
|
||||
|
||||
jlong newTimeout;
|
||||
jobject tokenObjLocal = env->NewLocalRef(tokenObjWeak);
|
||||
if (tokenObjLocal) {
|
||||
newTimeout = env->CallLongMethod(mCallbacksObj,
|
||||
gCallbacksClassInfo.notifyANR, tokenObjLocal);
|
||||
if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
|
||||
newTimeout = 0; // abort dispatch
|
||||
} else {
|
||||
assert(newTimeout >= 0);
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(tokenObjLocal);
|
||||
jobject tokenObjLocal;
|
||||
if (inputApplicationHandle.get()) {
|
||||
ApplicationToken* token = static_cast<ApplicationToken*>(inputApplicationHandle.get());
|
||||
jweak tokenObjWeak = token->getTokenObj();
|
||||
tokenObjLocal = env->NewLocalRef(tokenObjWeak);
|
||||
} else {
|
||||
newTimeout = 0; // abort dispatch
|
||||
tokenObjLocal = NULL;
|
||||
}
|
||||
|
||||
jobject inputChannelObjLocal;
|
||||
if (inputChannel.get()) {
|
||||
inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
|
||||
} else {
|
||||
inputChannelObjLocal = NULL;
|
||||
}
|
||||
|
||||
jlong newTimeout = env->CallLongMethod(mCallbacksObj,
|
||||
gCallbacksClassInfo.notifyANR, tokenObjLocal, inputChannelObjLocal);
|
||||
if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
|
||||
newTimeout = 0; // abort dispatch
|
||||
} else {
|
||||
assert(newTimeout >= 0);
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(tokenObjLocal);
|
||||
env->DeleteLocalRef(inputChannelObjLocal);
|
||||
return newTimeout;
|
||||
}
|
||||
|
||||
@@ -748,51 +755,6 @@ void NativeInputManager::notifyInputChannelBroken(const sp<InputChannel>& inputC
|
||||
}
|
||||
}
|
||||
|
||||
nsecs_t NativeInputManager::notifyInputChannelANR(const sp<InputChannel>& inputChannel) {
|
||||
#if DEBUG_INPUT_DISPATCHER_POLICY
|
||||
LOGD("notifyInputChannelANR - inputChannel='%s'",
|
||||
inputChannel->getName().string());
|
||||
#endif
|
||||
|
||||
JNIEnv* env = jniEnv();
|
||||
|
||||
jlong newTimeout;
|
||||
jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
|
||||
if (inputChannelObjLocal) {
|
||||
newTimeout = env->CallLongMethod(mCallbacksObj,
|
||||
gCallbacksClassInfo.notifyInputChannelANR, inputChannelObjLocal);
|
||||
if (checkAndClearExceptionFromCallback(env, "notifyInputChannelANR")) {
|
||||
newTimeout = 0; // abort dispatch
|
||||
} else {
|
||||
assert(newTimeout >= 0);
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(inputChannelObjLocal);
|
||||
} else {
|
||||
newTimeout = 0; // abort dispatch
|
||||
}
|
||||
|
||||
return newTimeout;
|
||||
}
|
||||
|
||||
void NativeInputManager::notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) {
|
||||
#if DEBUG_INPUT_DISPATCHER_POLICY
|
||||
LOGD("notifyInputChannelRecoveredFromANR - inputChannel='%s'",
|
||||
inputChannel->getName().string());
|
||||
#endif
|
||||
|
||||
JNIEnv* env = jniEnv();
|
||||
|
||||
jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
|
||||
if (inputChannelObjLocal) {
|
||||
env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyInputChannelRecoveredFromANR,
|
||||
inputChannelObjLocal);
|
||||
checkAndClearExceptionFromCallback(env, "notifyInputChannelRecoveredFromANR");
|
||||
|
||||
env->DeleteLocalRef(inputChannelObjLocal);
|
||||
}
|
||||
}
|
||||
|
||||
nsecs_t NativeInputManager::getKeyRepeatTimeout() {
|
||||
if (! isScreenOn()) {
|
||||
// Disable key repeat when the screen is off.
|
||||
@@ -855,6 +817,8 @@ bool NativeInputManager::populateWindow(JNIEnv* env, jobject windowObj,
|
||||
sp<InputChannel> inputChannel =
|
||||
android_view_InputChannel_getInputChannel(env, inputChannelObj);
|
||||
if (inputChannel != NULL) {
|
||||
jstring name = jstring(env->GetObjectField(windowObj,
|
||||
gInputWindowClassInfo.name));
|
||||
jint layoutParamsFlags = env->GetIntField(windowObj,
|
||||
gInputWindowClassInfo.layoutParamsFlags);
|
||||
jint layoutParamsType = env->GetIntField(windowObj,
|
||||
@@ -887,18 +851,25 @@ bool NativeInputManager::populateWindow(JNIEnv* env, jobject windowObj,
|
||||
gInputWindowClassInfo.touchableAreaBottom);
|
||||
jboolean visible = env->GetBooleanField(windowObj,
|
||||
gInputWindowClassInfo.visible);
|
||||
jboolean canReceiveKeys = env->GetBooleanField(windowObj,
|
||||
gInputWindowClassInfo.canReceiveKeys);
|
||||
jboolean hasFocus = env->GetBooleanField(windowObj,
|
||||
gInputWindowClassInfo.hasFocus);
|
||||
jboolean hasWallpaper = env->GetBooleanField(windowObj,
|
||||
gInputWindowClassInfo.hasWallpaper);
|
||||
jboolean paused = env->GetBooleanField(windowObj,
|
||||
gInputWindowClassInfo.paused);
|
||||
jint layer = env->GetIntField(windowObj,
|
||||
gInputWindowClassInfo.layer);
|
||||
jint ownerPid = env->GetIntField(windowObj,
|
||||
gInputWindowClassInfo.ownerPid);
|
||||
jint ownerUid = env->GetIntField(windowObj,
|
||||
gInputWindowClassInfo.ownerUid);
|
||||
|
||||
const char* nameStr = env->GetStringUTFChars(name, NULL);
|
||||
|
||||
outWindow.inputChannel = inputChannel;
|
||||
outWindow.name.setTo(nameStr);
|
||||
outWindow.layoutParamsFlags = layoutParamsFlags;
|
||||
outWindow.layoutParamsType = layoutParamsType;
|
||||
outWindow.dispatchingTimeout = dispatchingTimeoutNanos;
|
||||
@@ -915,11 +886,15 @@ bool NativeInputManager::populateWindow(JNIEnv* env, jobject windowObj,
|
||||
outWindow.touchableAreaRight = touchableAreaRight;
|
||||
outWindow.touchableAreaBottom = touchableAreaBottom;
|
||||
outWindow.visible = visible;
|
||||
outWindow.canReceiveKeys = canReceiveKeys;
|
||||
outWindow.hasFocus = hasFocus;
|
||||
outWindow.hasWallpaper = hasWallpaper;
|
||||
outWindow.paused = paused;
|
||||
outWindow.layer = layer;
|
||||
outWindow.ownerPid = ownerPid;
|
||||
outWindow.ownerUid = ownerUid;
|
||||
|
||||
env->ReleaseStringUTFChars(name, nameStr);
|
||||
valid = true;
|
||||
} else {
|
||||
LOGW("Dropping input target because its input channel is not initialized.");
|
||||
@@ -973,10 +948,6 @@ void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) {
|
||||
mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen);
|
||||
}
|
||||
|
||||
void NativeInputManager::preemptInputDispatch() {
|
||||
mInputManager->getDispatcher()->preemptInputDispatch();
|
||||
}
|
||||
|
||||
bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
|
||||
const KeyEvent* keyEvent, uint32_t policyFlags) {
|
||||
bool isScreenOn = this->isScreenOn();
|
||||
@@ -1246,15 +1217,6 @@ static void android_server_InputManager_nativeSetInputDispatchMode(JNIEnv* env,
|
||||
gNativeInputManager->setInputDispatchMode(enabled, frozen);
|
||||
}
|
||||
|
||||
static void android_server_InputManager_nativePreemptInputDispatch(JNIEnv* env,
|
||||
jclass clazz) {
|
||||
if (checkInputManagerUnitialized(env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
gNativeInputManager->preemptInputDispatch();
|
||||
}
|
||||
|
||||
static jobject android_server_InputManager_nativeGetInputDevice(JNIEnv* env,
|
||||
jclass clazz, jint deviceId) {
|
||||
if (checkInputManagerUnitialized(env)) {
|
||||
@@ -1357,8 +1319,6 @@ static JNINativeMethod gInputManagerMethods[] = {
|
||||
(void*) android_server_InputManager_nativeSetFocusedApplication },
|
||||
{ "nativeSetInputDispatchMode", "(ZZ)V",
|
||||
(void*) android_server_InputManager_nativeSetInputDispatchMode },
|
||||
{ "nativePreemptInputDispatch", "()V",
|
||||
(void*) android_server_InputManager_nativePreemptInputDispatch },
|
||||
{ "nativeGetInputDevice", "(I)Landroid/view/InputDevice;",
|
||||
(void*) android_server_InputManager_nativeGetInputDevice },
|
||||
{ "nativeGetInputDeviceIds", "()[I",
|
||||
@@ -1398,14 +1358,8 @@ int register_android_server_InputManager(JNIEnv* env) {
|
||||
GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, gCallbacksClassInfo.clazz,
|
||||
"notifyInputChannelBroken", "(Landroid/view/InputChannel;)V");
|
||||
|
||||
GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelANR, gCallbacksClassInfo.clazz,
|
||||
"notifyInputChannelANR", "(Landroid/view/InputChannel;)J");
|
||||
|
||||
GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelRecoveredFromANR, gCallbacksClassInfo.clazz,
|
||||
"notifyInputChannelRecoveredFromANR", "(Landroid/view/InputChannel;)V");
|
||||
|
||||
GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz,
|
||||
"notifyANR", "(Ljava/lang/Object;)J");
|
||||
"notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
|
||||
|
||||
GET_METHOD_ID(gCallbacksClassInfo.virtualKeyDownFeedback, gCallbacksClassInfo.clazz,
|
||||
"virtualKeyDownFeedback", "()V");
|
||||
@@ -1477,6 +1431,9 @@ int register_android_server_InputManager(JNIEnv* env) {
|
||||
GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz,
|
||||
"inputChannel", "Landroid/view/InputChannel;");
|
||||
|
||||
GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz,
|
||||
"name", "Ljava/lang/String;");
|
||||
|
||||
GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz,
|
||||
"layoutParamsFlags", "I");
|
||||
|
||||
@@ -1525,6 +1482,9 @@ int register_android_server_InputManager(JNIEnv* env) {
|
||||
GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz,
|
||||
"visible", "Z");
|
||||
|
||||
GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz,
|
||||
"canReceiveKeys", "Z");
|
||||
|
||||
GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz,
|
||||
"hasFocus", "Z");
|
||||
|
||||
@@ -1534,6 +1494,9 @@ int register_android_server_InputManager(JNIEnv* env) {
|
||||
GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz,
|
||||
"paused", "Z");
|
||||
|
||||
GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz,
|
||||
"layer", "I");
|
||||
|
||||
GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz,
|
||||
"ownerPid", "I");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user