am 9c258710: Merge "Fix app switch latency optimization." into gingerbread
Merge commit '9c2587104ae259b9fa6a3525063197cc08e8820b' into gingerbread-plus-aosp * commit '9c2587104ae259b9fa6a3525063197cc08e8820b': Fix app switch latency optimization.
This commit is contained in:
@@ -851,8 +851,8 @@ private:
|
|||||||
|
|
||||||
// Inbound event processing.
|
// Inbound event processing.
|
||||||
void drainInboundQueueLocked();
|
void drainInboundQueueLocked();
|
||||||
void releasePendingEventLocked(bool wasDropped);
|
void releasePendingEventLocked();
|
||||||
void releaseInboundEventLocked(EventEntry* entry, bool wasDropped);
|
void releaseInboundEventLocked(EventEntry* entry);
|
||||||
bool isEventFromReliableSourceLocked(EventEntry* entry);
|
bool isEventFromReliableSourceLocked(EventEntry* entry);
|
||||||
|
|
||||||
// Dispatch state.
|
// Dispatch state.
|
||||||
@@ -886,10 +886,10 @@ private:
|
|||||||
nsecs_t currentTime, ConfigurationChangedEntry* entry);
|
nsecs_t currentTime, ConfigurationChangedEntry* entry);
|
||||||
bool dispatchKeyLocked(
|
bool dispatchKeyLocked(
|
||||||
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
|
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
|
||||||
nsecs_t* nextWakeupTime);
|
bool dropEvent, nsecs_t* nextWakeupTime);
|
||||||
bool dispatchMotionLocked(
|
bool dispatchMotionLocked(
|
||||||
nsecs_t currentTime, MotionEntry* entry,
|
nsecs_t currentTime, MotionEntry* entry,
|
||||||
nsecs_t* nextWakeupTime);
|
bool dropEvent, nsecs_t* nextWakeupTime);
|
||||||
void dispatchEventToCurrentInputTargetsLocked(
|
void dispatchEventToCurrentInputTargetsLocked(
|
||||||
nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
|
nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
|
||||||
|
|
||||||
@@ -914,8 +914,8 @@ private:
|
|||||||
bool mInputTargetWaitTimeoutExpired;
|
bool mInputTargetWaitTimeoutExpired;
|
||||||
|
|
||||||
// Finding targets for input events.
|
// Finding targets for input events.
|
||||||
void startFindingTargetsLocked();
|
void resetTargetsLocked();
|
||||||
void finishFindingTargetsLocked(const InputWindow* window);
|
void commitTargetsLocked(const InputWindow* window);
|
||||||
int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
|
int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
|
||||||
const InputApplication* application, const InputWindow* window,
|
const InputApplication* application, const InputWindow* window,
|
||||||
nsecs_t* nextWakeupTime);
|
nsecs_t* nextWakeupTime);
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ InputDispatcher::~InputDispatcher() {
|
|||||||
AutoMutex _l(mLock);
|
AutoMutex _l(mLock);
|
||||||
|
|
||||||
resetKeyRepeatLocked();
|
resetKeyRepeatLocked();
|
||||||
releasePendingEventLocked(true);
|
releasePendingEventLocked();
|
||||||
drainInboundQueueLocked();
|
drainInboundQueueLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
|
|||||||
if (! mDispatchEnabled) {
|
if (! mDispatchEnabled) {
|
||||||
if (mPendingEvent || ! mInboundQueue.isEmpty()) {
|
if (mPendingEvent || ! mInboundQueue.isEmpty()) {
|
||||||
LOGI("Dropping pending events because input dispatch is disabled.");
|
LOGI("Dropping pending events because input dispatch is disabled.");
|
||||||
releasePendingEventLocked(true);
|
releasePendingEventLocked();
|
||||||
drainInboundQueueLocked();
|
drainInboundQueueLocked();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -281,51 +281,50 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
|
|||||||
|
|
||||||
// Now we have an event to dispatch.
|
// Now we have an event to dispatch.
|
||||||
assert(mPendingEvent != NULL);
|
assert(mPendingEvent != NULL);
|
||||||
bool wasDispatched = false;
|
bool done = false;
|
||||||
bool wasDropped = false;
|
|
||||||
switch (mPendingEvent->type) {
|
switch (mPendingEvent->type) {
|
||||||
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
|
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
|
||||||
ConfigurationChangedEntry* typedEntry =
|
ConfigurationChangedEntry* typedEntry =
|
||||||
static_cast<ConfigurationChangedEntry*>(mPendingEvent);
|
static_cast<ConfigurationChangedEntry*>(mPendingEvent);
|
||||||
wasDispatched = dispatchConfigurationChangedLocked(currentTime, typedEntry);
|
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EventEntry::TYPE_KEY: {
|
case EventEntry::TYPE_KEY: {
|
||||||
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
|
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
|
||||||
if (isAppSwitchPendingLocked()) {
|
bool appSwitchKey = isAppSwitchKey(typedEntry->keyCode);
|
||||||
if (isAppSwitchKey(typedEntry->keyCode)) {
|
bool dropEvent = isAppSwitchDue && ! appSwitchKey;
|
||||||
|
done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, dropEvent,
|
||||||
|
nextWakeupTime);
|
||||||
|
if (done) {
|
||||||
|
if (dropEvent) {
|
||||||
|
LOGI("Dropped key because of pending overdue app switch.");
|
||||||
|
} else if (appSwitchKey) {
|
||||||
resetPendingAppSwitchLocked(true);
|
resetPendingAppSwitchLocked(true);
|
||||||
} else if (isAppSwitchDue) {
|
|
||||||
LOGI("Dropping key because of pending overdue app switch.");
|
|
||||||
wasDropped = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wasDispatched = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout,
|
|
||||||
nextWakeupTime);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EventEntry::TYPE_MOTION: {
|
case EventEntry::TYPE_MOTION: {
|
||||||
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
|
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
|
||||||
if (isAppSwitchDue) {
|
bool dropEvent = isAppSwitchDue;
|
||||||
LOGI("Dropping motion because of pending overdue app switch.");
|
done = dispatchMotionLocked(currentTime, typedEntry, dropEvent, nextWakeupTime);
|
||||||
wasDropped = true;
|
if (done) {
|
||||||
break;
|
if (dropEvent) {
|
||||||
|
LOGI("Dropped motion because of pending overdue app switch.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
wasDispatched = dispatchMotionLocked(currentTime, typedEntry, nextWakeupTime);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
wasDropped = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wasDispatched || wasDropped) {
|
if (done) {
|
||||||
releasePendingEventLocked(wasDropped);
|
releasePendingEventLocked();
|
||||||
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
|
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,21 +402,21 @@ InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command comman
|
|||||||
void InputDispatcher::drainInboundQueueLocked() {
|
void InputDispatcher::drainInboundQueueLocked() {
|
||||||
while (! mInboundQueue.isEmpty()) {
|
while (! mInboundQueue.isEmpty()) {
|
||||||
EventEntry* entry = mInboundQueue.dequeueAtHead();
|
EventEntry* entry = mInboundQueue.dequeueAtHead();
|
||||||
releaseInboundEventLocked(entry, true /*wasDropped*/);
|
releaseInboundEventLocked(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputDispatcher::releasePendingEventLocked(bool wasDropped) {
|
void InputDispatcher::releasePendingEventLocked() {
|
||||||
if (mPendingEvent) {
|
if (mPendingEvent) {
|
||||||
releaseInboundEventLocked(mPendingEvent, wasDropped);
|
releaseInboundEventLocked(mPendingEvent);
|
||||||
mPendingEvent = NULL;
|
mPendingEvent = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputDispatcher::releaseInboundEventLocked(EventEntry* entry, bool wasDropped) {
|
void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) {
|
||||||
if (wasDropped) {
|
if (entry->injectionResult == INPUT_EVENT_INJECTION_PENDING) {
|
||||||
#if DEBUG_DISPATCH_CYCLE
|
#if DEBUG_DISPATCH_CYCLE
|
||||||
LOGD("Pending event was dropped.");
|
LOGD("Inbound event was dropped. Setting injection result to failed.");
|
||||||
#endif
|
#endif
|
||||||
setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
|
setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
|
||||||
}
|
}
|
||||||
@@ -492,7 +491,41 @@ bool InputDispatcher::dispatchConfigurationChangedLocked(
|
|||||||
|
|
||||||
bool InputDispatcher::dispatchKeyLocked(
|
bool InputDispatcher::dispatchKeyLocked(
|
||||||
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
|
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
|
||||||
nsecs_t* nextWakeupTime) {
|
bool dropEvent, nsecs_t* nextWakeupTime) {
|
||||||
|
// Give the policy a chance to intercept the key.
|
||||||
|
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
|
||||||
|
bool trusted;
|
||||||
|
if (! dropEvent && mFocusedWindow) {
|
||||||
|
trusted = checkInjectionPermission(mFocusedWindow,
|
||||||
|
entry->injectorPid, entry->injectorUid);
|
||||||
|
} else {
|
||||||
|
trusted = isEventFromReliableSourceLocked(entry);
|
||||||
|
}
|
||||||
|
if (trusted) {
|
||||||
|
CommandEntry* commandEntry = postCommandLocked(
|
||||||
|
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
|
||||||
|
if (! dropEvent && mFocusedWindow) {
|
||||||
|
commandEntry->inputChannel = mFocusedWindow->inputChannel;
|
||||||
|
}
|
||||||
|
commandEntry->keyEntry = entry;
|
||||||
|
entry->refCount += 1;
|
||||||
|
return false; // wait for the command to run
|
||||||
|
} else {
|
||||||
|
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
|
||||||
|
}
|
||||||
|
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
|
||||||
|
resetTargetsLocked();
|
||||||
|
setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_SUCCEEDED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up if dropping the event.
|
||||||
|
if (dropEvent) {
|
||||||
|
resetTargetsLocked();
|
||||||
|
setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Preprocessing.
|
// Preprocessing.
|
||||||
if (! entry->dispatchInProgress) {
|
if (! entry->dispatchInProgress) {
|
||||||
logOutboundKeyDetailsLocked("dispatchKey - ", entry);
|
logOutboundKeyDetailsLocked("dispatchKey - ", entry);
|
||||||
@@ -521,7 +554,7 @@ bool InputDispatcher::dispatchKeyLocked(
|
|||||||
}
|
}
|
||||||
|
|
||||||
entry->dispatchInProgress = true;
|
entry->dispatchInProgress = true;
|
||||||
startFindingTargetsLocked(); // resets mCurrentInputTargetsValid
|
resetTargetsLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identify targets.
|
// Identify targets.
|
||||||
@@ -539,20 +572,7 @@ bool InputDispatcher::dispatchKeyLocked(
|
|||||||
}
|
}
|
||||||
|
|
||||||
addMonitoringTargetsLocked();
|
addMonitoringTargetsLocked();
|
||||||
finishFindingTargetsLocked(window);
|
commitTargetsLocked(window);
|
||||||
}
|
|
||||||
|
|
||||||
// Give the policy a chance to intercept the key.
|
|
||||||
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
|
|
||||||
CommandEntry* commandEntry = postCommandLocked(
|
|
||||||
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
|
|
||||||
commandEntry->inputChannel = mCurrentInputChannel;
|
|
||||||
commandEntry->keyEntry = entry;
|
|
||||||
entry->refCount += 1;
|
|
||||||
return false; // wait for the command to run
|
|
||||||
}
|
|
||||||
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch the key.
|
// Dispatch the key.
|
||||||
@@ -576,13 +596,20 @@ void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyE
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool InputDispatcher::dispatchMotionLocked(
|
bool InputDispatcher::dispatchMotionLocked(
|
||||||
nsecs_t currentTime, MotionEntry* entry, nsecs_t* nextWakeupTime) {
|
nsecs_t currentTime, MotionEntry* entry, bool dropEvent, nsecs_t* nextWakeupTime) {
|
||||||
|
// Clean up if dropping the event.
|
||||||
|
if (dropEvent) {
|
||||||
|
resetTargetsLocked();
|
||||||
|
setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Preprocessing.
|
// Preprocessing.
|
||||||
if (! entry->dispatchInProgress) {
|
if (! entry->dispatchInProgress) {
|
||||||
logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
|
logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
|
||||||
|
|
||||||
entry->dispatchInProgress = true;
|
entry->dispatchInProgress = true;
|
||||||
startFindingTargetsLocked(); // resets mCurrentInputTargetsValid
|
resetTargetsLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
|
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
|
||||||
@@ -610,7 +637,7 @@ bool InputDispatcher::dispatchMotionLocked(
|
|||||||
}
|
}
|
||||||
|
|
||||||
addMonitoringTargetsLocked();
|
addMonitoringTargetsLocked();
|
||||||
finishFindingTargetsLocked(window);
|
commitTargetsLocked(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch the motion.
|
// Dispatch the motion.
|
||||||
@@ -705,14 +732,14 @@ void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputDispatcher::startFindingTargetsLocked() {
|
void InputDispatcher::resetTargetsLocked() {
|
||||||
mCurrentInputTargetsValid = false;
|
mCurrentInputTargetsValid = false;
|
||||||
mCurrentInputTargets.clear();
|
mCurrentInputTargets.clear();
|
||||||
mCurrentInputChannel.clear();
|
mCurrentInputChannel.clear();
|
||||||
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
|
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputDispatcher::finishFindingTargetsLocked(const InputWindow* window) {
|
void InputDispatcher::commitTargetsLocked(const InputWindow* window) {
|
||||||
mCurrentInputWindowType = window->layoutParamsType;
|
mCurrentInputWindowType = window->layoutParamsType;
|
||||||
mCurrentInputChannel = window->inputChannel;
|
mCurrentInputChannel = window->inputChannel;
|
||||||
mCurrentInputTargetsValid = true;
|
mCurrentInputTargetsValid = true;
|
||||||
|
|||||||
@@ -408,10 +408,15 @@ status_t NativeInputManager::unregisterInputChannel(JNIEnv* env,
|
|||||||
|
|
||||||
jobject NativeInputManager::getInputChannelObjLocal(JNIEnv* env,
|
jobject NativeInputManager::getInputChannelObjLocal(JNIEnv* env,
|
||||||
const sp<InputChannel>& inputChannel) {
|
const sp<InputChannel>& inputChannel) {
|
||||||
|
InputChannel* inputChannelPtr = inputChannel.get();
|
||||||
|
if (! inputChannelPtr) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
AutoMutex _l(mInputChannelRegistryLock);
|
AutoMutex _l(mInputChannelRegistryLock);
|
||||||
|
|
||||||
ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannel.get());
|
ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannelPtr);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -718,13 +723,7 @@ nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApp
|
|||||||
tokenObjLocal = NULL;
|
tokenObjLocal = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject inputChannelObjLocal;
|
jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
|
||||||
if (inputChannel.get()) {
|
|
||||||
inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel);
|
|
||||||
} else {
|
|
||||||
inputChannelObjLocal = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
jlong newTimeout = env->CallLongMethod(mCallbacksObj,
|
jlong newTimeout = env->CallLongMethod(mCallbacksObj,
|
||||||
gCallbacksClassInfo.notifyANR, tokenObjLocal, inputChannelObjLocal);
|
gCallbacksClassInfo.notifyANR, tokenObjLocal, inputChannelObjLocal);
|
||||||
if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
|
if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
|
||||||
@@ -957,23 +956,17 @@ bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& i
|
|||||||
|
|
||||||
JNIEnv* env = jniEnv();
|
JNIEnv* env = jniEnv();
|
||||||
|
|
||||||
|
// Note: inputChannel may be null.
|
||||||
jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel);
|
jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel);
|
||||||
if (inputChannelObj) {
|
jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
|
||||||
jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
|
gCallbacksClassInfo.interceptKeyBeforeDispatching,
|
||||||
gCallbacksClassInfo.interceptKeyBeforeDispatching,
|
inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
|
||||||
inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
|
keyEvent->getKeyCode(), keyEvent->getMetaState(),
|
||||||
keyEvent->getKeyCode(), keyEvent->getMetaState(),
|
keyEvent->getRepeatCount(), policyFlags);
|
||||||
keyEvent->getRepeatCount(), policyFlags);
|
bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
|
||||||
bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
|
|
||||||
|
|
||||||
env->DeleteLocalRef(inputChannelObj);
|
env->DeleteLocalRef(inputChannelObj);
|
||||||
|
return consumed && ! error;
|
||||||
return consumed && ! error;
|
|
||||||
} else {
|
|
||||||
LOGW("Could not apply key dispatch policy because input channel '%s' is "
|
|
||||||
"no longer valid.", inputChannel->getName().string());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t windowType, int32_t eventType) {
|
void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t windowType, int32_t eventType) {
|
||||||
|
|||||||
Reference in New Issue
Block a user