summaryrefslogtreecommitdiffstats
path: root/services/input
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2011-08-31 13:01:16 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-08-31 13:01:16 -0700
commit9d4bc852ea459c2a4347a87ce0357b3328a25db8 (patch)
tree30f7154a210380d638c54107cd670681cd557d72 /services/input
parent16b241a58f1ec4b317647b6fd0ad9b5cc3f7ba3d (diff)
parentcc4f7db698f88b633a286d8ab1105b28a474cd09 (diff)
downloadframeworks_base-9d4bc852ea459c2a4347a87ce0357b3328a25db8.zip
frameworks_base-9d4bc852ea459c2a4347a87ce0357b3328a25db8.tar.gz
frameworks_base-9d4bc852ea459c2a4347a87ce0357b3328a25db8.tar.bz2
Merge "Fix input channel leak. Bug: 5156144"
Diffstat (limited to 'services/input')
-rw-r--r--services/input/Android.mk1
-rw-r--r--services/input/InputApplication.cpp42
-rw-r--r--services/input/InputApplication.h36
-rw-r--r--services/input/InputDispatcher.cpp365
-rw-r--r--services/input/InputDispatcher.h11
-rw-r--r--services/input/InputWindow.cpp28
-rw-r--r--services/input/InputWindow.h54
7 files changed, 370 insertions, 167 deletions
diff --git a/services/input/Android.mk b/services/input/Android.mk
index afbe546..86c6c8a 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -18,6 +18,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
EventHub.cpp \
+ InputApplication.cpp \
InputDispatcher.cpp \
InputListener.cpp \
InputManager.cpp \
diff --git a/services/input/InputApplication.cpp b/services/input/InputApplication.cpp
new file mode 100644
index 0000000..a99e637
--- /dev/null
+++ b/services/input/InputApplication.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputApplication"
+
+#include "InputApplication.h"
+
+#include <cutils/log.h>
+
+namespace android {
+
+// --- InputApplicationHandle ---
+
+InputApplicationHandle::InputApplicationHandle() :
+ mInfo(NULL) {
+}
+
+InputApplicationHandle::~InputApplicationHandle() {
+ delete mInfo;
+}
+
+void InputApplicationHandle::releaseInfo() {
+ if (mInfo) {
+ delete mInfo;
+ mInfo = NULL;
+ }
+}
+
+} // namespace android
diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h
index 8902f7a..67ae94b 100644
--- a/services/input/InputApplication.h
+++ b/services/input/InputApplication.h
@@ -27,14 +27,32 @@ namespace android {
/*
* Describes the properties of an application that can receive input.
+ */
+struct InputApplicationInfo {
+ String8 name;
+ nsecs_t dispatchingTimeout;
+};
+
+
+/*
+ * Handle for an application that can receive input.
*
* Used by the native input dispatcher as a handle for the window manager objects
* that describe an application.
*/
class InputApplicationHandle : public RefBase {
public:
- String8 name;
- nsecs_t dispatchingTimeout;
+ inline const InputApplicationInfo* getInfo() const {
+ return mInfo;
+ }
+
+ inline String8 getName() const {
+ return mInfo ? mInfo->name : String8("<invalid>");
+ }
+
+ inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
+ return mInfo ? mInfo->dispatchingTimeout : defaultValue;
+ }
/**
* Requests that the state of this object be updated to reflect
@@ -45,11 +63,19 @@ public:
*
* Returns true on success, or false if the handle is no longer valid.
*/
- virtual bool update() = 0;
+ virtual bool updateInfo() = 0;
+
+ /**
+ * Releases the storage used by the associated information when it is
+ * no longer needed.
+ */
+ void releaseInfo();
protected:
- InputApplicationHandle() { }
- virtual ~InputApplicationHandle() { }
+ InputApplicationHandle();
+ virtual ~InputApplicationHandle();
+
+ InputApplicationInfo* mInfo;
};
} // namespace android
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index cf167ae..1eb5f0e 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -306,7 +306,12 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
}
}
}
+
+ // Nothing to do if there is no pending event.
if (! mPendingEvent) {
+ if (mActiveConnections.isEmpty()) {
+ dispatchIdleLocked();
+ }
return;
}
} else {
@@ -462,6 +467,16 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
}
}
+void InputDispatcher::dispatchIdleLocked() {
+#if DEBUG_FOCUS
+ LOGD("Dispatcher idle. There are no pending events or active connections.");
+#endif
+
+ // Reset targets when idle, to release input channels and other resources
+ // they are holding onto.
+ resetTargetsLocked();
+}
+
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
@@ -525,20 +540,21 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t x, int3
size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
- int32_t flags = windowHandle->layoutParamsFlags;
-
- if (windowHandle->visible) {
- if (!(flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) {
- bool isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE
- | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) {
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ int32_t flags = windowInfo->layoutParamsFlags;
+
+ if (windowInfo->visible) {
+ if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
+ bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
+ | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
+ if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
// Found window.
return windowHandle;
}
}
}
- if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) {
+ if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) {
// Error window is on top but not visible, so touch is dropped.
return NULL;
}
@@ -1051,9 +1067,15 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
LOGD("Waiting for application to become ready for input: %s",
getApplicationWindowLabelLocked(applicationHandle, windowHandle).string());
#endif
- nsecs_t timeout = windowHandle != NULL ? windowHandle->dispatchingTimeout :
- applicationHandle != NULL ?
- applicationHandle->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT;
+ nsecs_t timeout;
+ if (windowHandle != NULL) {
+ timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
+ } else if (applicationHandle != NULL) {
+ timeout = applicationHandle->getDispatchingTimeout(
+ DEFAULT_INPUT_DISPATCHING_TIMEOUT);
+ } else {
+ timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;
+ }
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
mInputTargetWaitStartTime = currentTime;
@@ -1168,7 +1190,7 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
}
// If the currently focused window is paused then keep waiting.
- if (mFocusedWindowHandle->paused) {
+ if (mFocusedWindowHandle->getInfo()->paused) {
#if DEBUG_FOCUS
LOGD("Waiting because focused window is paused.");
#endif
@@ -1302,21 +1324,22 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
- int32_t flags = windowHandle->layoutParamsFlags;
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ int32_t flags = windowInfo->layoutParamsFlags;
- if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) {
+ if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) {
if (topErrorWindowHandle == NULL) {
topErrorWindowHandle = windowHandle;
}
}
- if (windowHandle->visible) {
- if (! (flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) {
- isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE
- | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) {
+ if (windowInfo->visible) {
+ if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
+ isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
+ | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
+ if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
if (! screenWasOff
- || (flags & InputWindowHandle::FLAG_TOUCHABLE_WHEN_WAKING)) {
+ || (flags & InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING)) {
newTouchedWindowHandle = windowHandle;
}
break; // found touched window, exit window loop
@@ -1324,7 +1347,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
}
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- && (flags & InputWindowHandle::FLAG_WATCH_OUTSIDE_TOUCH)) {
+ && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
@@ -1350,7 +1373,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
}
// Figure out whether splitting will be allowed for this window.
- if (newTouchedWindowHandle != NULL && newTouchedWindowHandle->supportsSplitTouch()) {
+ if (newTouchedWindowHandle != NULL
+ && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
// New window supports splitting.
isSplit = true;
} else if (isSplit) {
@@ -1396,7 +1420,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
// within the touched window.
if (!isTouchModal) {
while (sample->next) {
- if (!newHoverWindowHandle->touchableRegionContainsPoint(
+ if (!newHoverWindowHandle->getInfo()->touchableRegionContainsPoint(
sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) {
*outSplitBatchAfterSample = sample;
@@ -1444,15 +1468,15 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
&& newTouchedWindowHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Touch is slipping out of window %s into window %s.",
- oldTouchedWindowHandle->name.string(),
- newTouchedWindowHandle->name.string());
+ oldTouchedWindowHandle->getName().string(),
+ newTouchedWindowHandle->getName().string());
#endif
// Make a slippery exit from the old window.
mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0));
// Make a slippery entrance into the new window.
- if (newTouchedWindowHandle->supportsSplitTouch()) {
+ if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
isSplit = true;
}
@@ -1484,7 +1508,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
// Let the previous window know that the hover sequence is over.
if (mLastHoverWindowHandle != NULL) {
#if DEBUG_HOVER
- LOGD("Sending hover exit event to window %s.", mLastHoverWindowHandle->name.string());
+ LOGD("Sending hover exit event to window %s.",
+ mLastHoverWindowHandle->getName().string());
#endif
mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
@@ -1493,7 +1518,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
// Let the new window know that the hover sequence is starting.
if (newHoverWindowHandle != NULL) {
#if DEBUG_HOVER
- LOGD("Sending hover enter event to window %s.", newHoverWindowHandle->name.string());
+ LOGD("Sending hover enter event to window %s.",
+ newHoverWindowHandle->getName().string());
#endif
mTempTouchState.addOrUpdateWindow(newHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
@@ -1533,12 +1559,12 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
- const int32_t foregroundWindowUid = foregroundWindowHandle->ownerUid;
+ const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
- if (inputWindowHandle->ownerUid != foregroundWindowUid) {
+ if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {
mTempTouchState.addOrUpdateWindow(inputWindowHandle,
InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
}
@@ -1551,7 +1577,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
// If the touched window is paused then keep waiting.
- if (touchedWindow.windowHandle->paused) {
+ if (touchedWindow.windowHandle->getInfo()->paused) {
#if DEBUG_FOCUS
LOGD("Waiting because touched window is paused.");
#endif
@@ -1581,10 +1607,11 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
- if (foregroundWindowHandle->hasWallpaper) {
+ if (foregroundWindowHandle->getInfo()->hasWallpaper) {
for (size_t i = 0; i < mWindowHandles.size(); i++) {
sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
- if (windowHandle->layoutParamsType == InputWindowHandle::TYPE_WALLPAPER) {
+ if (windowHandle->getInfo()->layoutParamsType
+ == InputWindowInfo::TYPE_WALLPAPER) {
mTempTouchState.addOrUpdateWindow(windowHandle,
InputTarget::FLAG_WINDOW_IS_OBSCURED
| InputTarget::FLAG_DISPATCH_AS_IS,
@@ -1708,12 +1735,13 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH
int32_t targetFlags, BitSet32 pointerIds) {
mCurrentInputTargets.push();
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
InputTarget& target = mCurrentInputTargets.editTop();
- target.inputChannel = windowHandle->inputChannel;
+ target.inputChannel = windowInfo->inputChannel;
target.flags = targetFlags;
- target.xOffset = - windowHandle->frameLeft;
- target.yOffset = - windowHandle->frameTop;
- target.scaleFactor = windowHandle->scaleFactor;
+ target.xOffset = - windowInfo->frameLeft;
+ target.yOffset = - windowInfo->frameTop;
+ target.scaleFactor = windowInfo->scaleFactor;
target.pointerIds = pointerIds;
}
@@ -1734,14 +1762,15 @@ void InputDispatcher::addMonitoringTargetsLocked() {
bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
const InjectionState* injectionState) {
if (injectionState
- && (windowHandle == NULL || windowHandle->ownerUid != injectionState->injectorUid)
+ && (windowHandle == NULL
+ || windowHandle->getInfo()->ownerUid != injectionState->injectorUid)
&& !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
if (windowHandle != NULL) {
LOGW("Permission denied: injecting event from pid %d uid %d to window %s "
"owned by uid %d",
injectionState->injectorPid, injectionState->injectorUid,
- windowHandle->name.string(),
- windowHandle->ownerUid);
+ windowHandle->getName().string(),
+ windowHandle->getInfo()->ownerUid);
} else {
LOGW("Permission denied: injecting event from pid %d uid %d",
injectionState->injectorPid, injectionState->injectorUid);
@@ -1759,8 +1788,10 @@ bool InputDispatcher::isWindowObscuredAtPointLocked(
if (otherHandle == windowHandle) {
break;
}
- if (otherHandle->visible && ! otherHandle->isTrustedOverlay()
- && otherHandle->frameContainsPoint(x, y)) {
+
+ const InputWindowInfo* otherInfo = otherHandle->getInfo();
+ if (otherInfo->visible && ! otherInfo->isTrustedOverlay()
+ && otherInfo->frameContainsPoint(x, y)) {
return true;
}
}
@@ -1769,7 +1800,7 @@ bool InputDispatcher::isWindowObscuredAtPointLocked(
bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(
const sp<InputWindowHandle>& windowHandle) {
- ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->inputChannel);
+ ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
return connection->outboundQueue.isEmpty();
@@ -1783,15 +1814,15 @@ String8 InputDispatcher::getApplicationWindowLabelLocked(
const sp<InputWindowHandle>& windowHandle) {
if (applicationHandle != NULL) {
if (windowHandle != NULL) {
- String8 label(applicationHandle->name);
+ String8 label(applicationHandle->getName());
label.append(" - ");
- label.append(windowHandle->name);
+ label.append(windowHandle->getName());
return label;
} else {
- return applicationHandle->name;
+ return applicationHandle->getName();
}
} else if (windowHandle != NULL) {
- return windowHandle->name;
+ return windowHandle->getName();
} else {
return String8("<unknown application or window>");
}
@@ -2127,7 +2158,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
if (status) {
LOGE("channel '%s' ~ Could not publish key event, "
"status=%d", connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
return;
}
break;
@@ -2190,7 +2221,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
if (status) {
LOGE("channel '%s' ~ Could not publish motion event, "
"status=%d", connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
return;
}
@@ -2223,7 +2254,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
LOGE("channel '%s' ~ Could not append motion sample "
"for a reason other than out of memory, status=%d",
connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
return;
}
}
@@ -2245,7 +2276,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
if (status) {
LOGE("channel '%s' ~ Could not send dispatch signal, status=%d",
connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
return;
}
@@ -2280,7 +2311,7 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
if (status) {
LOGE("channel '%s' ~ Could not reset publisher, status=%d",
connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
return;
}
@@ -2324,10 +2355,10 @@ void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime,
}
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
+ const sp<Connection>& connection, bool notify) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ abortBrokenDispatchCycle",
- connection->getInputChannelName());
+ LOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",
+ connection->getInputChannelName(), toString(notify));
#endif
// Clear the outbound queue.
@@ -2338,8 +2369,10 @@ void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
if (connection->status == Connection::STATUS_NORMAL) {
connection->status = Connection::STATUS_BROKEN;
- // Notify other system components.
- onDispatchCycleBrokenLocked(currentTime, connection);
+ if (notify) {
+ // Notify other system components.
+ onDispatchCycleBrokenLocked(currentTime, connection);
+ }
}
}
@@ -2368,36 +2401,41 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data
return 0; // remove the callback
}
- nsecs_t currentTime = now();
-
+ bool notify;
sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
- if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
- LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. "
- "events=0x%x", connection->getInputChannelName(), events);
- d->abortBrokenDispatchCycleLocked(currentTime, connection);
- d->runCommandsLockedInterruptible();
- return 0; // remove the callback
- }
+ if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
+ if (!(events & ALOOPER_EVENT_INPUT)) {
+ LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
+ "events=0x%x", connection->getInputChannelName(), events);
+ return 1;
+ }
- if (! (events & ALOOPER_EVENT_INPUT)) {
- LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
- "events=0x%x", connection->getInputChannelName(), events);
- return 1;
- }
+ bool handled = false;
+ status_t status = connection->inputPublisher.receiveFinishedSignal(&handled);
+ if (!status) {
+ nsecs_t currentTime = now();
+ d->finishDispatchCycleLocked(currentTime, connection, handled);
+ d->runCommandsLockedInterruptible();
+ return 1;
+ }
- bool handled = false;
- status_t status = connection->inputPublisher.receiveFinishedSignal(&handled);
- if (status) {
LOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName(), status);
- d->abortBrokenDispatchCycleLocked(currentTime, connection);
- d->runCommandsLockedInterruptible();
- return 0; // remove the callback
+ notify = true;
+ } else {
+ // Monitor channels are never explicitly unregistered.
+ // We do it automatically when the remote endpoint is closed so don't warn
+ // about them.
+ notify = !connection->monitor;
+ if (notify) {
+ LOGW("channel '%s' ~ Consumer closed input channel or an error occurred. "
+ "events=0x%x", connection->getInputChannelName(), events);
+ }
}
- d->finishDispatchCycleLocked(currentTime, connection, handled);
- d->runCommandsLockedInterruptible();
- return 1;
+ // Unregister the channel.
+ d->unregisterInputChannelLocked(connection->inputChannel, notify);
+ return 0; // remove the callback
} // release lock
}
@@ -2450,9 +2488,10 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
InputTarget target;
sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel);
if (windowHandle != NULL) {
- target.xOffset = -windowHandle->frameLeft;
- target.yOffset = -windowHandle->frameTop;
- target.scaleFactor = windowHandle->scaleFactor;
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ target.xOffset = -windowInfo->frameLeft;
+ target.yOffset = -windowInfo->frameTop;
+ target.scaleFactor = windowInfo->scaleFactor;
} else {
target.xOffset = 0;
target.yOffset = 0;
@@ -2854,9 +2893,9 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
#if DEBUG_BATCHING
LOGD("Not streaming hover move because the last hovered window "
"is '%s' but the currently hovered window is '%s'.",
- mLastHoverWindowHandle->name.string(),
+ mLastHoverWindowHandle->getName().string(),
hoverWindowHandle != NULL
- ? hoverWindowHandle->name.string() : "<null>");
+ ? hoverWindowHandle->getName().string() : "<null>");
#endif
goto NoBatchingOrStreaming;
}
@@ -3183,7 +3222,7 @@ sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
- if (windowHandle->inputChannel == inputChannel) {
+ if (windowHandle->getInputChannel() == inputChannel) {
return windowHandle;
}
}
@@ -3208,17 +3247,18 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inpu
{ // acquire lock
AutoMutex _l(mLock);
+ Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
mWindowHandles = inputWindowHandles;
sp<InputWindowHandle> newFocusedWindowHandle;
bool foundHoveredWindow = false;
for (size_t i = 0; i < mWindowHandles.size(); i++) {
const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
- if (!windowHandle->update() || windowHandle->inputChannel == NULL) {
+ if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) {
mWindowHandles.removeAt(i--);
continue;
}
- if (windowHandle->hasFocus) {
+ if (windowHandle->getInfo()->hasFocus) {
newFocusedWindowHandle = windowHandle;
}
if (windowHandle == mLastHoverWindowHandle) {
@@ -3234,19 +3274,20 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inpu
if (mFocusedWindowHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Focus left window: %s",
- mFocusedWindowHandle->name.string());
+ mFocusedWindowHandle->getName().string());
#endif
- if (mFocusedWindowHandle->inputChannel != NULL) {
+ sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
+ if (focusedInputChannel != NULL) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
synthesizeCancelationEventsForInputChannelLocked(
- mFocusedWindowHandle->inputChannel, options);
+ focusedInputChannel, options);
}
}
if (newFocusedWindowHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Focus entered window: %s",
- newFocusedWindowHandle->name.string());
+ newFocusedWindowHandle->getName().string());
#endif
}
mFocusedWindowHandle = newFocusedWindowHandle;
@@ -3256,17 +3297,34 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inpu
TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
#if DEBUG_FOCUS
- LOGD("Touched window was removed: %s", touchedWindow.windowHandle->name.string());
+ LOGD("Touched window was removed: %s",
+ touchedWindow.windowHandle->getName().string());
#endif
- if (touchedWindow.windowHandle->inputChannel != NULL) {
+ sp<InputChannel> touchedInputChannel =
+ touchedWindow.windowHandle->getInputChannel();
+ if (touchedInputChannel != NULL) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"touched window was removed");
synthesizeCancelationEventsForInputChannelLocked(
- touchedWindow.windowHandle->inputChannel, options);
+ touchedInputChannel, options);
}
mTouchState.windows.removeAt(i--);
}
}
+
+ // Release information for windows that are no longer present.
+ // This ensures that unused input channels are released promptly.
+ // Otherwise, they might stick around until the window handle is destroyed
+ // which might not happen until the next GC.
+ for (size_t i = 0; i < oldWindowHandles.size(); i++) {
+ const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
+ if (!hasWindowHandleLocked(oldWindowHandle)) {
+#if DEBUG_FOCUS
+ LOGD("Window went away: %s", oldWindowHandle->getName().string());
+#endif
+ oldWindowHandle->releaseInfo();
+ }
+ }
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
@@ -3281,15 +3339,17 @@ void InputDispatcher::setFocusedApplication(
{ // acquire lock
AutoMutex _l(mLock);
- if (inputApplicationHandle != NULL && inputApplicationHandle->update()) {
+ if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) {
if (mFocusedApplicationHandle != inputApplicationHandle) {
if (mFocusedApplicationHandle != NULL) {
resetTargetsLocked();
+ mFocusedApplicationHandle->releaseInfo();
}
mFocusedApplicationHandle = inputApplicationHandle;
}
} else if (mFocusedApplicationHandle != NULL) {
resetTargetsLocked();
+ mFocusedApplicationHandle->releaseInfo();
mFocusedApplicationHandle.clear();
}
@@ -3469,13 +3529,14 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
if (mFocusedApplicationHandle != NULL) {
dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
- mFocusedApplicationHandle->name.string(),
- mFocusedApplicationHandle->dispatchingTimeout / 1000000.0);
+ mFocusedApplicationHandle->getName().string(),
+ mFocusedApplicationHandle->getDispatchingTimeout(
+ DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0);
} else {
dump.append(INDENT "FocusedApplication: <null>\n");
}
dump.appendFormat(INDENT "FocusedWindow: name='%s'\n",
- mFocusedWindowHandle != NULL ? mFocusedWindowHandle->name.string() : "<null>");
+ mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : "<null>");
dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down));
dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split));
@@ -3486,7 +3547,8 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
for (size_t i = 0; i < mTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTouchState.windows[i];
dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
- i, touchedWindow.windowHandle->name.string(), touchedWindow.pointerIds.value,
+ i, touchedWindow.windowHandle->getName().string(),
+ touchedWindow.pointerIds.value,
touchedWindow.targetFlags);
}
} else {
@@ -3497,26 +3559,28 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
dump.append(INDENT "Windows:\n");
for (size_t i = 0; i < mWindowHandles.size(); i++) {
const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+
dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
"frame=[%d,%d][%d,%d], scale=%f, "
"touchableRegion=",
- i, windowHandle->name.string(),
- toString(windowHandle->paused),
- toString(windowHandle->hasFocus),
- toString(windowHandle->hasWallpaper),
- toString(windowHandle->visible),
- toString(windowHandle->canReceiveKeys),
- windowHandle->layoutParamsFlags, windowHandle->layoutParamsType,
- windowHandle->layer,
- windowHandle->frameLeft, windowHandle->frameTop,
- windowHandle->frameRight, windowHandle->frameBottom,
- windowHandle->scaleFactor);
- dumpRegion(dump, windowHandle->touchableRegion);
- dump.appendFormat(", inputFeatures=0x%08x", windowHandle->inputFeatures);
+ i, windowInfo->name.string(),
+ toString(windowInfo->paused),
+ toString(windowInfo->hasFocus),
+ toString(windowInfo->hasWallpaper),
+ toString(windowInfo->visible),
+ toString(windowInfo->canReceiveKeys),
+ windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
+ windowInfo->layer,
+ windowInfo->frameLeft, windowInfo->frameTop,
+ windowInfo->frameRight, windowInfo->frameBottom,
+ windowInfo->scaleFactor);
+ dumpRegion(dump, windowInfo->touchableRegion);
+ dump.appendFormat(", inputFeatures=0x%08x", windowInfo->inputFeatures);
dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
- windowHandle->ownerPid, windowHandle->ownerUid,
- windowHandle->dispatchingTimeout / 1000000.0);
+ windowInfo->ownerPid, windowInfo->ownerUid,
+ windowInfo->dispatchingTimeout / 1000000.0);
}
} else {
dump.append(INDENT "Windows: <none>\n");
@@ -3572,7 +3636,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan
return BAD_VALUE;
}
- sp<Connection> connection = new Connection(inputChannel, inputWindowHandle);
+ sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
status_t status = connection->initialize();
if (status) {
LOGE("Failed to initialize input publisher for input channel '%s', status=%d",
@@ -3602,39 +3666,54 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh
{ // acquire lock
AutoMutex _l(mLock);
- ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
- if (connectionIndex < 0) {
- LOGW("Attempted to unregister already unregistered input channel '%s'",
- inputChannel->getName().string());
- return BAD_VALUE;
+ status_t status = unregisterInputChannelLocked(inputChannel, false /*notify*/);
+ if (status) {
+ return status;
}
+ } // release lock
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
+ // Wake the poll loop because removing the connection may have changed the current
+ // synchronization state.
+ mLooper->wake();
+ return OK;
+}
- connection->status = Connection::STATUS_ZOMBIE;
+status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel,
+ bool notify) {
+ ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
+ if (connectionIndex < 0) {
+ LOGW("Attempted to unregister already unregistered input channel '%s'",
+ inputChannel->getName().string());
+ return BAD_VALUE;
+ }
- for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- if (mMonitoringChannels[i] == inputChannel) {
- mMonitoringChannels.removeAt(i);
- break;
- }
- }
+ sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+ mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
- mLooper->removeFd(inputChannel->getReceivePipeFd());
+ if (connection->monitor) {
+ removeMonitorChannelLocked(inputChannel);
+ }
- nsecs_t currentTime = now();
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ mLooper->removeFd(inputChannel->getReceivePipeFd());
- runCommandsLockedInterruptible();
- } // release lock
+ nsecs_t currentTime = now();
+ abortBrokenDispatchCycleLocked(currentTime, connection, notify);
- // Wake the poll loop because removing the connection may have changed the current
- // synchronization state.
- mLooper->wake();
+ runCommandsLockedInterruptible();
+
+ connection->status = Connection::STATUS_ZOMBIE;
return OK;
}
+void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) {
+ for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
+ if (mMonitoringChannels[i] == inputChannel) {
+ mMonitoringChannels.removeAt(i);
+ break;
+ }
+ }
+}
+
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
if (connectionIndex >= 0) {
@@ -3736,7 +3815,7 @@ void InputDispatcher::doNotifyANRLockedInterruptible(
resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
commandEntry->inputWindowHandle != NULL
- ? commandEntry->inputWindowHandle->inputChannel : NULL);
+ ? commandEntry->inputWindowHandle->getInputChannel() : NULL);
}
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -4495,8 +4574,9 @@ bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& mement
// --- InputDispatcher::Connection ---
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle) :
+ const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
+ monitor(monitor),
inputPublisher(inputChannel),
lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
}
@@ -4627,8 +4707,9 @@ bool InputDispatcher::TouchState::isSlippery() const {
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows.itemAt(i);
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
- if (haveSlipperyForegroundWindow || !(window.windowHandle->layoutParamsFlags
- & InputWindowHandle::FLAG_SLIPPERY)) {
+ if (haveSlipperyForegroundWindow
+ || !(window.windowHandle->getInfo()->layoutParamsFlags
+ & InputWindowInfo::FLAG_SLIPPERY)) {
return false;
}
haveSlipperyForegroundWindow = true;
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 3c83691..e78f7bd 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -814,6 +814,7 @@ private:
Status status;
sp<InputChannel> inputChannel; // never null
sp<InputWindowHandle> inputWindowHandle; // may be null
+ bool monitor;
InputPublisher inputPublisher;
InputState inputState;
Queue<DispatchEntry> outboundQueue;
@@ -822,7 +823,7 @@ private:
nsecs_t lastDispatchTime; // the time when the last event was dispatched
explicit Connection(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle);
+ const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
@@ -868,6 +869,7 @@ private:
Vector<EventEntry*> mTempCancelationEvents;
void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
+ void dispatchIdleLocked();
// Batches a new sample onto a motion entry.
// Assumes that the we have already checked that we can append samples.
@@ -1073,7 +1075,8 @@ private:
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool handled);
void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
- void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+ void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
+ bool notify);
void drainOutboundQueueLocked(Connection* connection);
static int handleReceiveCallback(int receiveFd, int events, void* data);
@@ -1094,6 +1097,10 @@ private:
void dumpDispatchStateLocked(String8& dump);
void logDispatchStateLocked();
+ // Registration.
+ void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel);
+ status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify);
+
// Add or remove a connection to the mActiveConnections vector.
void activateConnectionLocked(Connection* connection);
void deactivateConnectionLocked(Connection* connection);
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
index 0ce8867..fe61918 100644
--- a/services/input/InputWindow.cpp
+++ b/services/input/InputWindow.cpp
@@ -22,25 +22,43 @@
namespace android {
-// --- InputWindowHandle ---
+// --- InputWindowInfo ---
-bool InputWindowHandle::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
return touchableRegion.contains(x, y);
}
-bool InputWindowHandle::frameContainsPoint(int32_t x, int32_t y) const {
+bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
return x >= frameLeft && x <= frameRight
&& y >= frameTop && y <= frameBottom;
}
-bool InputWindowHandle::isTrustedOverlay() const {
+bool InputWindowInfo::isTrustedOverlay() const {
return layoutParamsType == TYPE_INPUT_METHOD
|| layoutParamsType == TYPE_INPUT_METHOD_DIALOG
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
}
-bool InputWindowHandle::supportsSplitTouch() const {
+bool InputWindowInfo::supportsSplitTouch() const {
return layoutParamsFlags & FLAG_SPLIT_TOUCH;
}
+
+// --- InputWindowHandle ---
+
+InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
+ inputApplicationHandle(inputApplicationHandle), mInfo(NULL) {
+}
+
+InputWindowHandle::~InputWindowHandle() {
+ delete mInfo;
+}
+
+void InputWindowHandle::releaseInfo() {
+ if (mInfo) {
+ delete mInfo;
+ mInfo = NULL;
+ }
+}
+
} // namespace android
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 272081c..8861bee 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -30,15 +30,9 @@
namespace android {
/*
- * A handle to a window that can receive input.
- *
- * Used by the native input dispatcher to indirectly refer to the window manager objects
- * that describe a window.
+ * Describes the properties of a window that can receive input.
*/
-class InputWindowHandle : public RefBase {
-public:
- const sp<InputApplicationHandle> inputApplicationHandle;
-
+struct InputWindowInfo {
// Window flags from WindowManager.LayoutParams
enum {
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
@@ -116,7 +110,6 @@ public:
INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
};
- sp<InputWindowHandle> inputWindowHandle;
sp<InputChannel> inputChannel;
String8 name;
int32_t layoutParamsFlags;
@@ -149,6 +142,34 @@ public:
bool isTrustedOverlay() const;
bool supportsSplitTouch() const;
+};
+
+
+/*
+ * Handle for a window that can receive input.
+ *
+ * Used by the native input dispatcher to indirectly refer to the window manager objects
+ * that describe a window.
+ */
+class InputWindowHandle : public RefBase {
+public:
+ const sp<InputApplicationHandle> inputApplicationHandle;
+
+ inline const InputWindowInfo* getInfo() const {
+ return mInfo;
+ }
+
+ inline sp<InputChannel> getInputChannel() const {
+ return mInfo ? mInfo->inputChannel : NULL;
+ }
+
+ inline String8 getName() const {
+ return mInfo ? mInfo->name : String8("<invalid>");
+ }
+
+ inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
+ return mInfo ? mInfo->dispatchingTimeout : defaultValue;
+ }
/**
* Requests that the state of this object be updated to reflect
@@ -159,12 +180,19 @@ public:
*
* Returns true on success, or false if the handle is no longer valid.
*/
- virtual bool update() = 0;
+ virtual bool updateInfo() = 0;
+
+ /**
+ * Releases the storage used by the associated information when it is
+ * no longer needed.
+ */
+ void releaseInfo();
protected:
- InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
- inputApplicationHandle(inputApplicationHandle) { }
- virtual ~InputWindowHandle() { }
+ InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
+ virtual ~InputWindowHandle();
+
+ InputWindowInfo* mInfo;
};
} // namespace android