Merge "Make input dispatcher only ANR for foreground windows." into gingerbread

This commit is contained in:
Jeff Brown
2010-09-15 18:55:25 -07:00
committed by Android (Google) Code Review
6 changed files with 387 additions and 660 deletions

View File

@@ -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

View File

@@ -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")

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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");