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:
Jeff Brown
2010-09-16 17:15:48 -07:00
committed by Android Git Automerger
3 changed files with 97 additions and 77 deletions

View File

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

View File

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

View File

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