diff options
Diffstat (limited to 'services')
50 files changed, 2871 insertions, 836 deletions
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk index 1af59a3..ed867d8 100644 --- a/services/inputflinger/Android.mk +++ b/services/inputflinger/Android.mk @@ -45,3 +45,5 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) LOCAL_MODULE := libinputflinger include $(BUILD_SHARED_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp index 93ce010..6b60c7c 100644 --- a/services/inputflinger/EventHub.cpp +++ b/services/inputflinger/EventHub.cpp @@ -131,6 +131,13 @@ uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { } } + // External stylus gets the pressure axis + if (deviceClasses & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + if (axis == ABS_PRESSURE) { + return INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; + } + } + // Joystick devices get the rest. return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK; } @@ -1185,6 +1192,16 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { && test_bit(ABS_X, device->absBitmask) && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; + // Is this a BT stylus? + } else if ((test_bit(ABS_PRESSURE, device->absBitmask) || + test_bit(BTN_TOUCH, device->keyBitmask)) + && !test_bit(ABS_X, device->absBitmask) + && !test_bit(ABS_Y, device->absBitmask)) { + device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; + // Keyboard will try to claim some of the buttons but we really want to reserve those so we + // can fuse it with the touch screen data, so just take them back. Note this means an + // external stylus cannot also be a keyboard device. + device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD; } // See if this device is a joystick. @@ -1279,6 +1296,11 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { return -1; } + // Determine whether the device has a mic. + if (deviceHasMicLocked(device)) { + device->classes |= INPUT_DEVICE_CLASS_MIC; + } + // Determine whether the device is external or internal. if (isExternalDeviceLocked(device)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; @@ -1293,7 +1315,10 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { // Register with epoll. struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP; + eventItem.events = EPOLLIN; + if (mUsingEpollWakeup) { + eventItem.events |= EPOLLWAKEUP; + } eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); @@ -1412,6 +1437,16 @@ bool EventHub::isExternalDeviceLocked(Device* device) { return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH; } +bool EventHub::deviceHasMicLocked(Device* device) { + if (device->configuration) { + bool value; + if (device->configuration->tryGetProperty(String8("audio.mic"), value)) { + return value; + } + } + return false; +} + int32_t EventHub::getNextControllerNumberLocked(Device* device) { if (mControllerNumbers.isFull()) { ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s", diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h index 20179ae..3ec4910 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -131,6 +131,12 @@ enum { /* The input device has a vibrator (supports FF_RUMBLE). */ INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, + /* The input device has a microphone. */ + INPUT_DEVICE_CLASS_MIC = 0x00000400, + + /* The input device is an external stylus (has data we want to fuse with touch data). */ + INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800, + /* The input device is virtual (not a real device, not part of UI configuration). */ INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, @@ -394,6 +400,7 @@ private: status_t loadKeyMapLocked(Device* device); bool isExternalDeviceLocked(Device* device); + bool deviceHasMicLocked(Device* device); int32_t getNextControllerNumberLocked(Device* device); void releaseControllerNumberLocked(Device* device); diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 9157bc1..0fba1bf 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -119,7 +119,7 @@ static bool validateKeyEvent(int32_t action) { return true; } -static bool isValidMotionAction(int32_t action, size_t pointerCount) { +static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) { switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_UP: @@ -136,14 +136,17 @@ static bool isValidMotionAction(int32_t action, size_t pointerCount) { int32_t index = getMotionEventActionPointerIndex(action); return index >= 0 && size_t(index) < pointerCount; } + case AMOTION_EVENT_ACTION_BUTTON_PRESS: + case AMOTION_EVENT_ACTION_BUTTON_RELEASE: + return actionButton != 0; default: return false; } } -static bool validateMotionEvent(int32_t action, size_t pointerCount, +static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount, const PointerProperties* pointerProperties) { - if (! isValidMotionAction(action, pointerCount)) { + if (! isValidMotionAction(action, actionButton, pointerCount)) { ALOGE("Motion event has invalid action code 0x%x", action); return false; } @@ -198,7 +201,8 @@ static void dumpRegion(String8& dump, const Region& region) { InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : mPolicy(policy), - mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), + mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED), + mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(NULL), mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { @@ -394,6 +398,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { if (dropReason != DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason); } + mLastDropReason = dropReason; releasePendingEventLocked(); *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately @@ -503,7 +508,9 @@ void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropR reason = "inbound event was dropped because the policy consumed it"; break; case DROP_REASON_DISABLED: - ALOGI("Dropped event because input dispatch is disabled."); + if (mLastDropReason != DROP_REASON_DISABLED) { + ALOGI("Dropped event because input dispatch is disabled."); + } reason = "inbound event was dropped because input dispatch is disabled"; break; case DROP_REASON_APP_SWITCH: @@ -852,6 +859,13 @@ bool InputDispatcher::dispatchMotionLocked( setInjectionResultLocked(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { + if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) { + CancelationOptions::Mode mode(isPointerEvent ? + CancelationOptions::CANCEL_POINTER_EVENTS : + CancelationOptions::CANCEL_NON_POINTER_EVENTS); + CancelationOptions options(mode, "input event injection failed"); + synthesizeCancelationEventsForMonitorsLocked(options); + } return true; } @@ -874,12 +888,12 @@ bool InputDispatcher::dispatchMotionLocked( void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, " - "metaState=0x%x, buttonState=0x%x, " + "action=0x%x, actionButton=0x%x, flags=0x%x, " + "metaState=0x%x, buttonState=0x%x," "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", prefix, entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, + entry->action, entry->actionButton, entry->flags, entry->metaState, entry->buttonState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, entry->downTime); @@ -1981,10 +1995,10 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, // Publish the motion event. status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, motionEntry->source, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, - motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, - xOffset, yOffset, - motionEntry->xPrecision, motionEntry->yPrecision, + dispatchEntry->resolvedAction, motionEntry->actionButton, + dispatchEntry->resolvedFlags, motionEntry->edgeFlags, + motionEntry->metaState, motionEntry->buttonState, + xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, motionEntry->downTime, motionEntry->eventTime, motionEntry->pointerCount, motionEntry->pointerProperties, usingCoords); @@ -2160,6 +2174,13 @@ void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( } } +void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked( + const CancelationOptions& options) { + for (size_t i = 0; i < mMonitoringChannels.size(); i++) { + synthesizeCancelationEventsForInputChannelLocked(mMonitoringChannels[i], options); + } +} + void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( const sp<InputChannel>& channel, const CancelationOptions& options) { ssize_t index = getConnectionIndexLocked(channel); @@ -2298,6 +2319,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet originalMotionEntry->source, originalMotionEntry->policyFlags, action, + originalMotionEntry->actionButton, originalMotionEntry->flags, originalMotionEntry->metaState, originalMotionEntry->buttonState, @@ -2432,10 +2454,10 @@ bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, " - "xPrecision=%f, yPrecision=%f, downTime=%lld", + "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", args->eventTime, args->deviceId, args->source, args->policyFlags, - args->action, args->flags, args->metaState, args->buttonState, + args->action, args->actionButton, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " @@ -2455,7 +2477,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif - if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) { + if (!validateMotionEvent(args->action, args->actionButton, + args->pointerCount, args->pointerProperties)) { return; } @@ -2471,9 +2494,9 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - event.initialize(args->deviceId, args->source, args->action, args->flags, - args->edgeFlags, args->metaState, args->buttonState, 0, 0, - args->xPrecision, args->yPrecision, + event.initialize(args->deviceId, args->source, args->action, args->actionButton, + args->flags, args->edgeFlags, args->metaState, args->buttonState, + 0, 0, args->xPrecision, args->yPrecision, args->downTime, args->eventTime, args->pointerCount, args->pointerProperties, args->pointerCoords); @@ -2488,7 +2511,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { // Just enqueue a new motion event. MotionEntry* newEntry = new MotionEntry(args->eventTime, args->deviceId, args->source, policyFlags, - args->action, args->flags, args->metaState, args->buttonState, + args->action, args->actionButton, args->flags, + args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, args->displayId, args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0); @@ -2589,7 +2613,8 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displ int32_t action = motionEvent->getAction(); size_t pointerCount = motionEvent->getPointerCount(); const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); - if (! validateMotionEvent(action, pointerCount, pointerProperties)) { + int32_t actionButton = motionEvent->getActionButton(); + if (! validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { return INPUT_EVENT_INJECTION_FAILED; } @@ -2603,7 +2628,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displ const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); firstInjectedEntry = new MotionEntry(*sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), + action, actionButton, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), @@ -2616,7 +2641,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displ samplePointerCoords += pointerCount; MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), + action, actionButton, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), @@ -3907,18 +3932,18 @@ void InputDispatcher::KeyEntry::recycle() { // --- InputDispatcher::MotionEntry --- -InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t buttonState, - int32_t edgeFlags, float xPrecision, float yPrecision, - nsecs_t downTime, int32_t displayId, uint32_t pointerCount, +InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t deviceId, + uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, + float xPrecision, float yPrecision, nsecs_t downTime, + int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xOffset, float yOffset) : EventEntry(TYPE_MOTION, eventTime, policyFlags), eventTime(eventTime), - deviceId(deviceId), source(source), action(action), flags(flags), - metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), - xPrecision(xPrecision), yPrecision(yPrecision), + deviceId(deviceId), source(source), action(action), actionButton(actionButton), + flags(flags), metaState(metaState), buttonState(buttonState), + edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime), displayId(displayId), pointerCount(pointerCount) { for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); @@ -3933,10 +3958,10 @@ InputDispatcher::MotionEntry::~MotionEntry() { } void InputDispatcher::MotionEntry::appendDescription(String8& msg) const { - msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, " - "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, edgeFlags=0x%08x, " - "xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[", - deviceId, source, action, flags, metaState, buttonState, edgeFlags, + msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, " + "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, " + "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[", + deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags, xPrecision, yPrecision, displayId); for (uint32_t i = 0; i < pointerCount; i++) { if (i) { @@ -4237,7 +4262,7 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL, - memento.flags, 0, 0, 0, + memento.flags, 0, 0, 0, 0, memento.xPrecision, memento.yPrecision, memento.downTime, memento.displayId, memento.pointerCount, memento.pointerProperties, memento.pointerCoords, diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 8c78a44..98355c6 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -504,6 +504,7 @@ private: int32_t deviceId; uint32_t source; int32_t action; + int32_t actionButton; int32_t flags; int32_t metaState; int32_t buttonState; @@ -518,10 +519,10 @@ private: MotionEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, + int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, - float xPrecision, float yPrecision, - nsecs_t downTime, int32_t displayId, uint32_t pointerCount, + float xPrecision, float yPrecision, nsecs_t downTime, + int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xOffset, float yOffset); virtual void appendDescription(String8& msg) const; @@ -856,6 +857,8 @@ private: Queue<EventEntry> mRecentQueue; Queue<CommandEntry> mCommandQueue; + DropReason mLastDropReason; + void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime); // Enqueues an inbound event. Returns true if mLooper->wake() should be called. @@ -1073,6 +1076,7 @@ private: void synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options); + void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options); void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, const CancelationOptions& options); void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp index 85bb0ed..dded47d 100644 --- a/services/inputflinger/InputListener.cpp +++ b/services/inputflinger/InputListener.cpp @@ -68,12 +68,13 @@ void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const { NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, + int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, + int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) : eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), - action(action), flags(flags), metaState(metaState), buttonState(buttonState), + action(action), actionButton(actionButton), + flags(flags), metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount), xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) { for (uint32_t i = 0; i < pointerCount; i++) { @@ -85,10 +86,9 @@ NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), policyFlags(other.policyFlags), - action(other.action), flags(other.flags), + action(other.action), actionButton(other.actionButton), flags(other.flags), metaState(other.metaState), buttonState(other.buttonState), - edgeFlags(other.edgeFlags), displayId(other.displayId), - pointerCount(other.pointerCount), + edgeFlags(other.edgeFlags), displayId(other.displayId), pointerCount(other.pointerCount), xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) { for (uint32_t i = 0; i < pointerCount; i++) { pointerProperties[i].copyFrom(other.pointerProperties[i]); diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h index 78ae10f..1ec09ce 100644 --- a/services/inputflinger/InputListener.h +++ b/services/inputflinger/InputListener.h @@ -84,6 +84,7 @@ struct NotifyMotionArgs : public NotifyArgs { uint32_t source; uint32_t policyFlags; int32_t action; + int32_t actionButton; int32_t flags; int32_t metaState; int32_t buttonState; @@ -99,7 +100,8 @@ struct NotifyMotionArgs : public NotifyArgs { inline NotifyMotionArgs() { } NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, + int32_t action, int32_t actionButton, int32_t flags, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime); diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index ccf8ced..bd74b02 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -39,12 +39,16 @@ // Log debug messages about the vibrator. #define DEBUG_VIBRATOR 0 +// Log debug messages about fusing stylus data. +#define DEBUG_STYLUS_FUSION 0 + #include "InputReader.h" #include <cutils/log.h> #include <input/Keyboard.h> #include <input/VirtualKeyMap.h> +#include <inttypes.h> #include <stddef.h> #include <stdlib.h> #include <unistd.h> @@ -65,6 +69,17 @@ namespace android { // Maximum number of slots supported when using the slot-based Multitouch Protocol B. static const size_t MAX_SLOTS = 32; +// Maximum amount of latency to add to touch events while waiting for data from an +// external stylus. +static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72); + +// Maximum amount of time to wait on touch data before pushing out new pressure data. +static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); + +// Artificial latency on synthetic events created from stylus data without corresponding touch +// data. +static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); + // --- Static Functions --- template<typename T> @@ -381,6 +396,10 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { mDevices.add(deviceId, device); bumpGenerationLocked(); + + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } } void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { @@ -403,6 +422,10 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { device->getId(), device->getName().string(), device->getSources()); } + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } + device->reset(when); delete device; } @@ -417,6 +440,11 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controlle device->setExternal(true); } + // Devices with mics. + if (classes & INPUT_DEVICE_CLASS_MIC) { + device->setMic(true); + } + // Switch-like devices. if (classes & INPUT_DEVICE_CLASS_SWITCH) { device->addMapper(new SwitchInputMapper(device)); @@ -464,6 +492,11 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controlle device->addMapper(new JoystickInputMapper(device)); } + // External stylus-like devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + device->addMapper(new ExternalStylusInputMapper(device)); + } + return device; } @@ -534,6 +567,27 @@ int32_t InputReader::getGlobalMetaStateLocked() { return mGlobalMetaState; } +void InputReader::notifyExternalStylusPresenceChanged() { + refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE); +} + +void InputReader::getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) { + outDevices.push(); + device->getDeviceInfo(&outDevices.editTop()); + } + } +} + +void InputReader::dispatchExternalStylusState(const StylusState& state) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->updateExternalStylusState(state); + } +} + void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { mDisableVirtualKeysTimeout = time; } @@ -824,6 +878,15 @@ int32_t InputReader::ContextImpl::bumpGeneration() { return mReader->bumpGenerationLocked(); } +void InputReader::ContextImpl::getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) { + // lock is already held by whatever called refreshConfigurationLocked + mReader->getExternalStylusDevicesLocked(outDevices); +} + +void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) { + mReader->dispatchExternalStylusState(state); +} + InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { return mReader->mPolicy.get(); } @@ -858,7 +921,7 @@ InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t genera int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) : mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber), mIdentifier(identifier), mClasses(classes), - mSources(0), mIsExternal(false), mDropUntilNextSync(false) { + mSources(0), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) { } InputDevice::~InputDevice() { @@ -877,6 +940,7 @@ void InputDevice::dump(String8& dump) { deviceInfo.getDisplayName().string()); dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration); dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); + dump.appendFormat(INDENT2 "HasMic: %s\n", toString(mHasMic)); dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); @@ -1006,10 +1070,17 @@ void InputDevice::timeoutExpired(nsecs_t when) { } } +void InputDevice::updateExternalStylusState(const StylusState& state) { + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->updateExternalStylusState(state); + } +} + void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, - mIsExternal); - + mIsExternal, mHasMic); size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; @@ -1285,7 +1356,9 @@ void TouchButtonAccumulator::configure(InputDevice* device) { void TouchButtonAccumulator::reset(InputDevice* device) { mBtnTouch = device->isKeyPressed(BTN_TOUCH); mBtnStylus = device->isKeyPressed(BTN_STYLUS); - mBtnStylus2 = device->isKeyPressed(BTN_STYLUS); + // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch + mBtnStylus2 = + device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0); mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); @@ -1326,6 +1399,7 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) { mBtnStylus = rawEvent->value; break; case BTN_STYLUS2: + case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch mBtnStylus2 = rawEvent->value; break; case BTN_TOOL_FINGER: @@ -1368,10 +1442,10 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) { uint32_t TouchButtonAccumulator::getButtonState() const { uint32_t result = 0; if (mBtnStylus) { - result |= AMOTION_EVENT_BUTTON_SECONDARY; + result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY; } if (mBtnStylus2) { - result |= AMOTION_EVENT_BUTTON_TERTIARY; + result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY; } return result; } @@ -1801,6 +1875,10 @@ int32_t InputMapper::getMetaState() { return 0; } +void InputMapper::updateExternalStylusState(const StylusState& state) { + +} + void InputMapper::fadePointer() { } @@ -1822,6 +1900,12 @@ void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, } } +void InputMapper::dumpStylusState(String8& dump, const StylusState& state) { + dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when); + dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure); + dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons); + dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); +} // --- SwitchInputMapper --- @@ -2463,7 +2547,8 @@ void CursorInputMapper::sync(nsecs_t when) { } nsecs_t downTime = mDownTime; bool buttonsChanged = currentButtonState != lastButtonState; - bool buttonsPressed = currentButtonState & ~lastButtonState; + int32_t buttonsPressed = currentButtonState & ~lastButtonState; + int32_t buttonsReleased = lastButtonState & ~currentButtonState; float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; @@ -2539,6 +2624,7 @@ void CursorInputMapper::sync(nsecs_t when) { // Send motion event. if (downChanged || moved || scrolled || buttonsChanged) { int32_t metaState = mContext->getGlobalMetaState(); + int32_t buttonState = lastButtonState; int32_t motionEventAction; if (downChanged) { motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; @@ -2548,17 +2634,48 @@ void CursorInputMapper::sync(nsecs_t when) { motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; } + if (buttonsReleased) { + BitSet32 released(buttonsReleased); + while (!released.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); + buttonState &= ~actionButton; + NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + displayId, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, downTime); + getListener()->notifyMotion(&releaseArgs); + } + } + NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - motionEventAction, 0, metaState, currentButtonState, 0, + motionEventAction, 0, 0, metaState, currentButtonState, + AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&args); + if (buttonsPressed) { + BitSet32 pressed(buttonsPressed); + while (!pressed.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); + buttonState |= actionButton; + NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + displayId, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, downTime); + getListener()->notifyMotion(&pressArgs); + } + } + + ALOG_ASSERT(buttonState == currentButtonState); + // Send hover move after UP to tell the application that the mouse is hovering now. if (motionEventAction == AMOTION_EVENT_ACTION_UP && mPointerController != NULL) { NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); @@ -2571,7 +2688,7 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState, + AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); @@ -2703,12 +2820,11 @@ void TouchInputMapper::dump(String8& dump) { dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); - dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState); - + dump.appendFormat(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState); dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n", - mLastRawPointerData.pointerCount); - for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) { - const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i]; + mLastRawState.rawPointerData.pointerCount); + for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) { + const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " @@ -2720,11 +2836,13 @@ void TouchInputMapper::dump(String8& dump) { pointer.toolType, toString(pointer.isHovering)); } + dump.appendFormat(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState); dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n", - mLastCookedPointerData.pointerCount); - for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) { - const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i]; - const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i]; + mLastCookedState.cookedPointerData.pointerCount); + for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) { + const PointerProperties& pointerProperties = + mLastCookedState.cookedPointerData.pointerProperties[i]; + const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " @@ -2741,9 +2859,18 @@ void TouchInputMapper::dump(String8& dump) { pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), pointerProperties.toolType, - toString(mLastCookedPointerData.isHovering(i))); + toString(mLastCookedState.cookedPointerData.isHovering(i))); } + dump.append(INDENT3 "Stylus Fusion:\n"); + dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n", + toString(mExternalStylusConnected)); + dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); + dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", + mExternalStylusFusionTimeout); + dump.append(INDENT3 "External Stylus State:\n"); + dumpStylusState(dump, mExternalStylusState); + if (mDeviceMode == DEVICE_MODE_POINTER) { dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", @@ -2781,7 +2908,7 @@ void TouchInputMapper::configure(nsecs_t when, resolveCalibration(); } - if (!changes || (changes & InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION)) { + if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) { // Update location calibration to reflect current settings updateAffineTransformation(); } @@ -2796,7 +2923,8 @@ void TouchInputMapper::configure(nsecs_t when, bool resetNeeded = false; if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT - | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) { + | InputReaderConfiguration::CHANGE_SHOW_TOUCHES + | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { // Configure device sources, surface dimensions, orientation and // scaling factors. configureSurface(when, &resetNeeded); @@ -2809,6 +2937,16 @@ void TouchInputMapper::configure(nsecs_t when, } } +void TouchInputMapper::resolveExternalStylusPresence() { + Vector<InputDeviceInfo> devices; + mContext->getExternalStylusDevices(devices); + mExternalStylusConnected = !devices.isEmpty(); + + if (!mExternalStylusConnected) { + resetExternalStylus(); + } +} + void TouchInputMapper::configureParameters() { // Use the pointer presentation mode for devices that do not support distinct // multitouch. The spot-based presentation relies on being able to accurately @@ -2945,9 +3083,15 @@ void TouchInputMapper::dumpRawPointerAxes(String8& dump) { dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); } +bool TouchInputMapper::hasExternalStylus() const { + return mExternalStylusConnected; +} + void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t oldDeviceMode = mDeviceMode; + resolveExternalStylusPresence(); + // Determine device mode. if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER && mConfig.pointerGesturesEnabled) { @@ -2963,6 +3107,9 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } + if (hasExternalStylus()) { + mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS; + } } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; mDeviceMode = DEVICE_MODE_NAVIGATION; @@ -3705,28 +3852,22 @@ void TouchInputMapper::reset(nsecs_t when) { mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); - mCurrentRawPointerData.clear(); - mLastRawPointerData.clear(); - mCurrentCookedPointerData.clear(); - mLastCookedPointerData.clear(); - mCurrentButtonState = 0; - mLastButtonState = 0; - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; - mCurrentFingerIdBits.clear(); - mLastFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mLastStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mLastMouseIdBits.clear(); + mRawStatesPending.clear(); + mCurrentRawState.clear(); + mCurrentCookedState.clear(); + mLastRawState.clear(); + mLastCookedState.clear(); mPointerUsage = POINTER_USAGE_NONE; mSentHoverEnter = false; + mHavePointerIds = false; + mCurrentMotionAborted = false; mDownTime = 0; mCurrentVirtualKey.down = false; mPointerGesture.reset(); mPointerSimple.reset(); + resetExternalStylus(); if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); @@ -3736,6 +3877,18 @@ void TouchInputMapper::reset(nsecs_t when) { InputMapper::reset(when); } +void TouchInputMapper::resetExternalStylus() { + mExternalStylusState.clear(); + mExternalStylusId = -1; + mExternalStylusFusionTimeout = LLONG_MAX; + mExternalStylusDataPending = false; +} + +void TouchInputMapper::clearStylusDataPendingFlags() { + mExternalStylusDataPending = false; + mExternalStylusFusionTimeout = LLONG_MAX; +} + void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); @@ -3747,155 +3900,288 @@ void TouchInputMapper::process(const RawEvent* rawEvent) { } void TouchInputMapper::sync(nsecs_t when) { + const RawState* last = mRawStatesPending.isEmpty() ? + &mCurrentRawState : &mRawStatesPending.top(); + + // Push a new state. + mRawStatesPending.push(); + RawState* next = &mRawStatesPending.editTop(); + next->clear(); + next->when = when; + // Sync button state. - mCurrentButtonState = mTouchButtonAccumulator.getButtonState() + next->buttonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); - // Sync scroll state. - mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); - mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); + // Sync scroll + next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); + next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); mCursorScrollAccumulator.finishSync(); - // Sync touch state. - bool havePointerIds = true; - mCurrentRawPointerData.clear(); - syncTouch(when, &havePointerIds); + // Sync touch + syncTouch(when, next); -#if DEBUG_RAW_EVENTS - if (!havePointerIds) { - ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount); - } else { - ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount, - mLastRawPointerData.touchingIdBits.value, - mCurrentRawPointerData.touchingIdBits.value, - mLastRawPointerData.hoveringIdBits.value, - mCurrentRawPointerData.hoveringIdBits.value); + // Assign pointer ids. + if (!mHavePointerIds) { + assignPointerIds(last, next); } + +#if DEBUG_RAW_EVENTS + ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " + "hovering ids 0x%08x -> 0x%08x", + last->rawPointerData.pointerCount, + next->rawPointerData.pointerCount, + last->rawPointerData.touchingIdBits.value, + next->rawPointerData.touchingIdBits.value, + last->rawPointerData.hoveringIdBits.value, + next->rawPointerData.hoveringIdBits.value); #endif - // Reset state that we will compute below. - mCurrentFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mCurrentCookedPointerData.clear(); + processRawTouches(false /*timeout*/); +} +void TouchInputMapper::processRawTouches(bool timeout) { if (mDeviceMode == DEVICE_MODE_DISABLED) { // Drop all input if the device is disabled. - mCurrentRawPointerData.clear(); - mCurrentButtonState = 0; - } else { - // Preprocess pointer data. - if (!havePointerIds) { - assignPointerIds(); - } - - // Handle policy on initial down or hover events. - uint32_t policyFlags = 0; - bool initialDown = mLastRawPointerData.pointerCount == 0 - && mCurrentRawPointerData.pointerCount != 0; - bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; - if (initialDown || buttonsPressed) { - // If this is a touch screen, hide the pointer on an initial down. - if (mDeviceMode == DEVICE_MODE_DIRECT) { - getContext()->fadePointer(); - } + mCurrentRawState.clear(); + mRawStatesPending.clear(); + return; + } - if (mParameters.wake) { - policyFlags |= POLICY_FLAG_WAKE; - } + // Drain any pending touch states. The invariant here is that the mCurrentRawState is always + // valid and must go through the full cook and dispatch cycle. This ensures that anything + // touching the current state will only observe the events that have been dispatched to the + // rest of the pipeline. + const size_t N = mRawStatesPending.size(); + size_t count; + for(count = 0; count < N; count++) { + const RawState& next = mRawStatesPending[count]; + + // A failure to assign the stylus id means that we're waiting on stylus data + // and so should defer the rest of the pipeline. + if (assignExternalStylusId(next, timeout)) { + break; + } + + // All ready to go. + clearStylusDataPendingFlags(); + mCurrentRawState.copyFrom(next); + if (mCurrentRawState.when < mLastRawState.when) { + mCurrentRawState.when = mLastRawState.when; + } + cookAndDispatch(mCurrentRawState.when); + } + if (count != 0) { + mRawStatesPending.removeItemsAt(0, count); + } + + if (mExternalStylusDataPending) { + if (timeout) { + nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY; + clearStylusDataPendingFlags(); + mCurrentRawState.copyFrom(mLastRawState); +#if DEBUG_STYLUS_FUSION + ALOGD("Timeout expired, synthesizing event with new stylus data"); +#endif + cookAndDispatch(when); + } else if (mExternalStylusFusionTimeout == LLONG_MAX) { + mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT; + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); } + } +} + +void TouchInputMapper::cookAndDispatch(nsecs_t when) { + // Always start with a clean state. + mCurrentCookedState.clear(); + + // Apply stylus buttons to current raw state. + applyExternalStylusButtonState(when); + + // Handle policy on initial down or hover events. + bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 + && mCurrentRawState.rawPointerData.pointerCount != 0; - // Synthesize key down from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); + uint32_t policyFlags = 0; + bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState; + if (initialDown || buttonsPressed) { + // If this is a touch screen, hide the pointer on an initial down. + if (mDeviceMode == DEVICE_MODE_DIRECT) { + getContext()->fadePointer(); + } - // Consume raw off-screen touches before cooking pointer data. - // If touches are consumed, subsequent code will not receive any pointer data. - if (consumeRawTouches(when, policyFlags)) { - mCurrentRawPointerData.clear(); + if (mParameters.wake) { + policyFlags |= POLICY_FLAG_WAKE; } + } - // Cook pointer data. This call populates the mCurrentCookedPointerData structure - // with cooked pointer data that has the same ids and indices as the raw data. - // The following code can use either the raw or cooked data, as needed. - cookPointerData(); + // Consume raw off-screen touches before cooking pointer data. + // If touches are consumed, subsequent code will not receive any pointer data. + if (consumeRawTouches(when, policyFlags)) { + mCurrentRawState.rawPointerData.clear(); + } - // Dispatch the touches either directly or by translation through a pointer on screen. - if (mDeviceMode == DEVICE_MODE_POINTER) { - for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mCurrentFingerIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { - mCurrentMouseIdBits.markBit(id); - } + // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure + // with cooked pointer data that has the same ids and indices as the raw data. + // The following code can use either the raw or cooked data, as needed. + cookPointerData(); + + // Apply stylus pressure to current cooked state. + applyExternalStylusTouchState(when); + + // Synthesize key down from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, + policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState); + + // Dispatch the touches either directly or by translation through a pointer on screen. + if (mDeviceMode == DEVICE_MODE_POINTER) { + for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); + !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mCurrentCookedState.fingerIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { + mCurrentCookedState.mouseIdBits.markBit(id); } - for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } + } + for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); + !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); } + } - // Stylus takes precedence over all tools, then mouse, then finger. - PointerUsage pointerUsage = mPointerUsage; - if (!mCurrentStylusIdBits.isEmpty()) { - mCurrentMouseIdBits.clear(); - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_STYLUS; - } else if (!mCurrentMouseIdBits.isEmpty()) { - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_MOUSE; - } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) { - pointerUsage = POINTER_USAGE_GESTURES; - } + // Stylus takes precedence over all tools, then mouse, then finger. + PointerUsage pointerUsage = mPointerUsage; + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + mCurrentCookedState.mouseIdBits.clear(); + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_STYLUS; + } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_MOUSE; + } else if (!mCurrentCookedState.fingerIdBits.isEmpty() || + isPointerDown(mCurrentRawState.buttonState)) { + pointerUsage = POINTER_USAGE_GESTURES; + } - dispatchPointerUsage(when, policyFlags, pointerUsage); - } else { - if (mDeviceMode == DEVICE_MODE_DIRECT - && mConfig.showTouches && mPointerController != NULL) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - - mPointerController->setButtonState(mCurrentButtonState); - mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.touchingIdBits); - } + dispatchPointerUsage(when, policyFlags, pointerUsage); + } else { + if (mDeviceMode == DEVICE_MODE_DIRECT + && mConfig.showTouches && mPointerController != NULL) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + mPointerController->setButtonState(mCurrentRawState.buttonState); + mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits); + } + + if (!mCurrentMotionAborted) { + dispatchButtonRelease(when, policyFlags); dispatchHoverExit(when, policyFlags); dispatchTouches(when, policyFlags); dispatchHoverEnterAndMove(when, policyFlags); + dispatchButtonPress(when, policyFlags); } - // Synthesize key up from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); + if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { + mCurrentMotionAborted = false; + } } - // Copy current touch to last touch in preparation for the next cycle. - mLastRawPointerData.copyFrom(mCurrentRawPointerData); - mLastCookedPointerData.copyFrom(mCurrentCookedPointerData); - mLastButtonState = mCurrentButtonState; - mLastFingerIdBits = mCurrentFingerIdBits; - mLastStylusIdBits = mCurrentStylusIdBits; - mLastMouseIdBits = mCurrentMouseIdBits; + // Synthesize key up from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, + policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState); // Clear some transient state. - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; + mCurrentRawState.rawVScroll = 0; + mCurrentRawState.rawHScroll = 0; + + // Copy current touch to last touch in preparation for the next cycle. + mLastRawState.copyFrom(mCurrentRawState); + mLastCookedState.copyFrom(mCurrentCookedState); +} + +void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { + if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) { + mCurrentRawState.buttonState |= mExternalStylusState.buttons; + } +} + +void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { + CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData; + const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData; + + if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) { + float pressure = mExternalStylusState.pressure; + if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) { + const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId); + pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); + } + PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId); + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); + + PointerProperties& properties = + currentPointerData.editPointerPropertiesWithId(mExternalStylusId); + if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + properties.toolType = mExternalStylusState.toolType; + } + } +} + +bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) { + if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) { + return false; + } + + const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 + && state.rawPointerData.pointerCount != 0; + if (initialDown) { + if (mExternalStylusState.pressure != 0.0f) { +#if DEBUG_STYLUS_FUSION + ALOGD("Have both stylus and touch data, beginning fusion"); +#endif + mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit(); + } else if (timeout) { +#if DEBUG_STYLUS_FUSION + ALOGD("Timeout expired, assuming touch is not a stylus."); +#endif + resetExternalStylus(); + } else { + if (mExternalStylusFusionTimeout == LLONG_MAX) { + mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT; + } +#if DEBUG_STYLUS_FUSION + ALOGD("No stylus data but stylus is connected, requesting timeout " + "(%" PRId64 "ms)", mExternalStylusFusionTimeout); +#endif + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); + return true; + } + } + + // Check if the stylus pointer has gone up. + if (mExternalStylusId != -1 && + !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) { +#if DEBUG_STYLUS_FUSION + ALOGD("Stylus pointer is going up"); +#endif + mExternalStylusId = -1; + } + + return false; } void TouchInputMapper::timeoutExpired(nsecs_t when) { @@ -3903,13 +4189,30 @@ void TouchInputMapper::timeoutExpired(nsecs_t when) { if (mPointerUsage == POINTER_USAGE_GESTURES) { dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); } + } else if (mDeviceMode == DEVICE_MODE_DIRECT) { + if (mExternalStylusFusionTimeout < when) { + processRawTouches(true /*timeout*/); + } else if (mExternalStylusFusionTimeout != LLONG_MAX) { + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); + } + } +} + +void TouchInputMapper::updateExternalStylusState(const StylusState& state) { + mExternalStylusState.copyFrom(state); + if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) { + // We're either in the middle of a fused stream of data or we're waiting on data before + // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus + // data. + mExternalStylusDataPending = true; + processRawTouches(false /*timeout*/); } } bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // Check for release of a virtual key. if (mCurrentVirtualKey.down) { - if (mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { // Pointer went up while virtual key was down. mCurrentVirtualKey.down = false; if (!mCurrentVirtualKey.ignored) { @@ -3924,9 +4227,10 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { return true; } - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { // Pointer is still within the space of the virtual key. @@ -3951,15 +4255,15 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { } } - if (mLastRawPointerData.touchingIdBits.isEmpty() - && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() + && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { // Pointer just went down. Check for virtual key press or off-screen touches. - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); if (!isPointInsideSurface(pointer.x, pointer.y)) { // If exactly one pointer went down, check for virtual key hit. // Otherwise we will drop the entire stroke. - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey) { mCurrentVirtualKey.down = true; @@ -3999,7 +4303,8 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // area and accidentally triggers a virtual key. This often happens when virtual keys // are layed out below the screen near to where the on screen keyboard's space bar // is displayed. - if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mConfig.virtualKeyQuietTime > 0 && + !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); } return false; @@ -4018,22 +4323,38 @@ void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, getListener()->notifyKey(&args); } +void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) { + BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; + if (!currentIdBits.isEmpty()) { + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentCookedState.buttonState; + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + currentIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mCurrentMotionAborted = true; + } +} + void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits; - BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits; + BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; + BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits; int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentCookedState.buttonState; if (currentIdBits == lastIdBits) { if (!currentIdBits.isEmpty()) { // No pointer id changes so this is a move event. // The listener takes care of batching moves so we don't have to deal with that here. dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } @@ -4048,14 +4369,14 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool moveNeeded = updateMovedPointers( - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, moveIdBits); - if (buttonState != mLastButtonState) { + if (buttonState != mLastCookedState.buttonState) { moveNeeded = true; } @@ -4064,27 +4385,25 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { uint32_t upId = upIdBits.clearFirstMarkedBit(); dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - dispatchedIdBits, upId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, + dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); dispatchedIdBits.clearBit(upId); } // Dispatch move events if any of the remaining pointers moved from their old locations. // Although applications receive new locations as part of individual pointer up // events, they do not generally handle them except when presented in a move event. - if (moveNeeded) { + if (moveNeeded && !moveIdBits.isEmpty()) { ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - dispatchedIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } // Dispatch pointer down events using the new pointer locations. @@ -4098,69 +4417,119 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { } dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - dispatchedIdBits, downId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } } void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { if (mSentHoverEnter && - (mCurrentCookedPointerData.hoveringIdBits.isEmpty() - || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) { + (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() + || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) { int32_t metaState = getContext()->getGlobalMetaState(); dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - mLastCookedPointerData.hoveringIdBits, -1, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = false; } } void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { - if (mCurrentCookedPointerData.touchingIdBits.isEmpty() - && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) { + if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() + && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); if (!mSentHoverEnter) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, + 0, 0, metaState, mCurrentRawState.buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = true; } dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } +void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) { + BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState); + const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData); + const int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mLastCookedState.buttonState; + while (!releasedButtons.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit()); + buttonState &= ~actionButton; + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, + 0, metaState, buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } +} + +void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) { + BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState); + const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData); + const int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mLastCookedState.buttonState; + while (!pressedButtons.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit()); + buttonState |= actionButton; + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, + 0, metaState, buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } +} + +const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) { + if (!cookedPointerData.touchingIdBits.isEmpty()) { + return cookedPointerData.touchingIdBits; + } + return cookedPointerData.hoveringIdBits; +} + void TouchInputMapper::cookPointerData() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; + uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; + + mCurrentCookedState.cookedPointerData.clear(); + mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; + mCurrentCookedState.cookedPointerData.hoveringIdBits = + mCurrentRawState.rawPointerData.hoveringIdBits; + mCurrentCookedState.cookedPointerData.touchingIdBits = + mCurrentRawState.rawPointerData.touchingIdBits; - mCurrentCookedPointerData.clear(); - mCurrentCookedPointerData.pointerCount = currentPointerCount; - mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits; - mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits; + if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { + mCurrentCookedState.buttonState = 0; + } else { + mCurrentCookedState.buttonState = mCurrentRawState.buttonState; + } // Walk through the the active pointers and map device coordinates onto // surface coordinates and adjust for display orientation. for (uint32_t i = 0; i < currentPointerCount; i++) { - const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i]; + const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; // Size float touchMajor, touchMinor, toolMajor, toolMinor, size; @@ -4199,7 +4568,8 @@ void TouchInputMapper::cookPointerData() { } if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { - uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count(); + uint32_t touchingCount = + mCurrentRawState.rawPointerData.touchingIdBits.count(); if (touchingCount > 1) { touchMajor /= touchingCount; touchMinor /= touchingCount; @@ -4368,7 +4738,7 @@ void TouchInputMapper::cookPointerData() { } // Write output coords. - PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i]; + PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i]; out.clear(); out.setAxisValue(AMOTION_EVENT_AXIS_X, x); out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); @@ -4390,14 +4760,15 @@ void TouchInputMapper::cookPointerData() { } // Write output properties. - PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i]; + PointerProperties& properties = + mCurrentCookedState.cookedPointerData.pointerProperties[i]; uint32_t id = in.id; properties.clear(); properties.id = id; properties.toolType = in.toolType; // Write id index. - mCurrentCookedPointerData.idToIndex[id] = i; + mCurrentCookedState.cookedPointerData.idToIndex[id] = i; } } @@ -4501,7 +4872,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send events! int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentCookedState.buttonState; // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. @@ -4522,7 +4893,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, movedGestureIdBits); - if (buttonState != mLastButtonState) { + if (buttonState != mLastCookedState.buttonState) { moveNeeded = true; } } @@ -4532,12 +4903,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag if (!dispatchedGestureIdBits.isEmpty()) { if (cancelPreviousGesture) { dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, + AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); + dispatchedGestureIdBits, -1, 0, + 0, mPointerGesture.downTime); dispatchedGestureIdBits.clear(); } else { @@ -4552,7 +4923,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag uint32_t id = upGestureIdBits.clearFirstMarkedBit(); dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, + AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, @@ -4567,7 +4938,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send motion events for all pointers that moved. if (moveNeeded) { dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, + AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, @@ -4587,7 +4959,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag } dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, + AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, @@ -4598,7 +4970,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send motion events for hover. if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, @@ -4624,7 +4996,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mViewport.displayId, 1, &pointerProperties, &pointerCoords, 0, 0, mPointerGesture.downTime); @@ -4653,9 +5025,9 @@ void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) // Cancel previously dispatches pointers. if (!mPointerGesture.lastGestureIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentRawState.buttonState; dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, + AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, @@ -4710,21 +5082,22 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, return false; } - const uint32_t currentFingerCount = mCurrentFingerIdBits.count(); - const uint32_t lastFingerCount = mLastFingerIdBits.count(); + const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count(); + const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count(); // Update the velocity tracker. { VelocityTracker::Position positions[MAX_POINTERS]; uint32_t count = 0; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) { + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) { uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); positions[count].x = pointer.x * mPointerXMovementScale; positions[count].y = pointer.y * mPointerYMovementScale; } mPointerGesture.velocityTracker.addMovement(when, - mCurrentFingerIdBits, positions); + mCurrentCookedState.fingerIdBits, positions); } // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning @@ -4744,17 +5117,17 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, int32_t lastActiveTouchId = mPointerGesture.activeTouchId; int32_t activeTouchId = lastActiveTouchId; if (activeTouchId < 0) { - if (!mCurrentFingerIdBits.isEmpty()) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchChanged = true; activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); + mCurrentCookedState.fingerIdBits.firstMarkedBit(); mPointerGesture.firstTouchTime = when; } - } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) { + } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) { activeTouchChanged = true; - if (!mCurrentFingerIdBits.isEmpty()) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); + mCurrentCookedState.fingerIdBits.firstMarkedBit(); } else { activeTouchId = mPointerGesture.activeTouchId = -1; } @@ -4777,7 +5150,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, isQuietTime = true; } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG && currentFingerCount >= 2 - && !isPointerDown(mCurrentButtonState)) { + && !isPointerDown(mCurrentRawState.buttonState)) { // Enter quiet time when releasing the button and there are still two or more // fingers down. This may indicate that one finger was used to press the button // but it has not gone up yet. @@ -4805,7 +5178,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdBits.clear(); mPointerVelocityControl.reset(); - } else if (isPointerDown(mCurrentButtonState)) { + } else if (isPointerDown(mCurrentRawState.buttonState)) { // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) // The pointer follows the active touch point. // Emit DOWN, MOVE, UP events at the pointer location. @@ -4834,7 +5207,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, if (activeTouchId >= 0 && currentFingerCount > 1) { int32_t bestId = -1; float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) { + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); float vx, vy; if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { @@ -4855,11 +5228,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) { + if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); + mLastRawState.rawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; @@ -4995,11 +5368,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } - if (mLastFingerIdBits.hasBit(activeTouchId)) { + if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); + mLastRawState.rawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) @@ -5104,7 +5477,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, + mConfig.pointerGestureMultitouchSettleInterval - when) * 0.000001f); #endif - mCurrentRawPointerData.getCentroidOfTouchingPointers( + mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers( &mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); mPointerController->getPosition(&mPointerGesture.referenceGestureX, @@ -5112,23 +5485,23 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentFingerIdBits.value + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); mPointerGesture.referenceDeltas[id].dx = 0; mPointerGesture.referenceDeltas[id].dy = 0; } - mPointerGesture.referenceIdBits = mCurrentFingerIdBits; + mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits; // Add delta for all fingers and calculate a common movement delta. float commonDeltaX = 0, commonDeltaY = 0; - BitSet32 commonIdBits(mLastFingerIdBits.value - & mCurrentFingerIdBits.value); + BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value + & mCurrentCookedState.fingerIdBits.value); for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { bool first = (idBits == commonIdBits); uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id); - const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id); + const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id); + const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id); PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; delta.dx += cpd.x - lpd.x; delta.dy += cpd.y - lpd.y; @@ -5169,11 +5542,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } else { // There are exactly two pointers. - BitSet32 idBits(mCurrentFingerIdBits); + BitSet32 idBits(mCurrentCookedState.fingerIdBits); uint32_t id1 = idBits.clearFirstMarkedBit(); uint32_t id2 = idBits.firstMarkedBit(); - const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1); - const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2); + const RawPointerData::Pointer& p1 = + mCurrentRawState.rawPointerData.pointerForId(id1); + const RawPointerData::Pointer& p2 = + mCurrentRawState.rawPointerData.pointerForId(id2); float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); if (mutualDistance > mPointerGestureMaxSwipeWidth) { // There are two pointers but they are too far apart for a SWIPE, @@ -5319,14 +5694,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } else { // Otherwise, assume we mapped all touches from the previous frame. // Reuse all mappings that are still applicable. - mappedTouchIdBits.value = mLastFingerIdBits.value - & mCurrentFingerIdBits.value; + mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value + & mCurrentCookedState.fingerIdBits.value; usedGestureIdBits = mPointerGesture.lastGestureIdBits; // Check whether we need to choose a new active gesture id because the // current went went up. - for (BitSet32 upTouchIdBits(mLastFingerIdBits.value - & ~mCurrentFingerIdBits.value); + for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value + & ~mCurrentCookedState.fingerIdBits.value); !upTouchIdBits.isEmpty(); ) { uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; @@ -5345,7 +5720,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.activeGestureId); #endif - BitSet32 idBits(mCurrentFingerIdBits); + BitSet32 idBits(mCurrentCookedState.fingerIdBits); for (uint32_t i = 0; i < currentFingerCount; i++) { uint32_t touchId = idBits.clearFirstMarkedBit(); uint32_t gestureId; @@ -5369,7 +5744,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdToIndex[gestureId] = i; const RawPointerData::Pointer& pointer = - mCurrentRawPointerData.pointerForId(touchId); + mCurrentRawState.rawPointerData.pointerForId(touchId); float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale; float deltaY = (pointer.y - mPointerGesture.referenceTouchY) @@ -5400,7 +5775,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - mPointerController->setButtonState(mCurrentButtonState); + mPointerController->setButtonState(mCurrentRawState.buttonState); #if DEBUG_GESTURES ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " @@ -5442,23 +5817,24 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) mPointerSimple.currentProperties.clear(); bool down, hovering; - if (!mCurrentStylusIdBits.isEmpty()) { - uint32_t id = mCurrentStylusIdBits.firstMarkedBit(); - uint32_t index = mCurrentCookedPointerData.idToIndex[id]; - float x = mCurrentCookedPointerData.pointerCoords[index].getX(); - float y = mCurrentCookedPointerData.pointerCoords[index].getY(); + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); + uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; + float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(); + float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY(); mPointerController->setPosition(x, y); - hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id); + hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]); + mPointerSimple.currentCoords.copyFrom( + mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[index].toolType; + mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType; } else { down = false; hovering = false; @@ -5476,16 +5852,16 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) mPointerSimple.currentProperties.clear(); bool down, hovering; - if (!mCurrentMouseIdBits.isEmpty()) { - uint32_t id = mCurrentMouseIdBits.firstMarkedBit(); - uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id]; - if (mLastMouseIdBits.hasBit(id)) { - uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id]; - float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x - - mLastRawPointerData.pointers[lastIndex].x) + if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit(); + uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + if (mLastCookedState.mouseIdBits.hasBit(id)) { + uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + float deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x + - mLastRawState.rawPointerData.pointers[lastIndex].x) * mPointerXMovementScale; - float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y - - mLastRawPointerData.pointers[lastIndex].y) + float deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y + - mLastRawState.rawPointerData.pointers[lastIndex].y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); @@ -5496,20 +5872,20 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) mPointerVelocityControl.reset(); } - down = isPointerDown(mCurrentButtonState); + down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; float x, y; mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( - mCurrentCookedPointerData.pointerCoords[currentIndex]); + mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, hovering ? 0.0f : 1.0f); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[currentIndex].toolType; + mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType; } else { mPointerVelocityControl.reset(); @@ -5534,7 +5910,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, if (down || hovering) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentButtonState); + mPointerController->setButtonState(mCurrentRawState.buttonState); mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); @@ -5546,7 +5922,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send up. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0, + AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5559,7 +5935,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover exit. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5574,7 +5950,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send down. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5584,7 +5960,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5598,7 +5974,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover enter. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, + mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5608,7 +5985,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5616,9 +5994,9 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, getListener()->notifyMotion(&args); } - if (mCurrentRawVScroll || mCurrentRawHScroll) { - float vscroll = mCurrentRawVScroll; - float hscroll = mCurrentRawHScroll; + if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) { + float vscroll = mCurrentRawState.rawVScroll; + float hscroll = mCurrentRawState.rawHScroll; mWheelYVelocityControl.move(when, NULL, &vscroll); mWheelXVelocityControl.move(when, &hscroll, NULL); @@ -5629,7 +6007,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &pointerCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5654,10 +6032,11 @@ void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { } void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, + int32_t action, int32_t actionButton, int32_t flags, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, - int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { + const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, + float xPrecision, float yPrecision, nsecs_t downTime) { PointerCoords pointerCoords[MAX_POINTERS]; PointerProperties pointerProperties[MAX_POINTERS]; uint32_t pointerCount = 0; @@ -5691,7 +6070,7 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32 } NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, - action, flags, metaState, buttonState, edgeFlags, + action, actionButton, flags, metaState, buttonState, edgeFlags, mViewport.displayId, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); getListener()->notifyMotion(&args); @@ -5733,6 +6112,7 @@ void TouchInputMapper::fadePointer() { void TouchInputMapper::cancelTouch(nsecs_t when) { abortPointerUsage(when, 0 /*policyFlags*/); + abortTouches(when, 0 /* policyFlags*/); } bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { @@ -5763,11 +6143,11 @@ const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit( return NULL; } -void TouchInputMapper::assignPointerIds() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; - uint32_t lastPointerCount = mLastRawPointerData.pointerCount; +void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) { + uint32_t currentPointerCount = current->rawPointerData.pointerCount; + uint32_t lastPointerCount = last->rawPointerData.pointerCount; - mCurrentRawPointerData.clearIdBits(); + current->rawPointerData.clearIdBits(); if (currentPointerCount == 0) { // No pointers to assign. @@ -5778,21 +6158,21 @@ void TouchInputMapper::assignPointerIds() { // All pointers are new. for (uint32_t i = 0; i < currentPointerCount; i++) { uint32_t id = i; - mCurrentRawPointerData.pointers[i].id = id; - mCurrentRawPointerData.idToIndex[id] = i; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i)); + current->rawPointerData.pointers[i].id = id; + current->rawPointerData.idToIndex[id] = i; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i)); } return; } if (currentPointerCount == 1 && lastPointerCount == 1 - && mCurrentRawPointerData.pointers[0].toolType - == mLastRawPointerData.pointers[0].toolType) { + && current->rawPointerData.pointers[0].toolType + == last->rawPointerData.pointers[0].toolType) { // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = mLastRawPointerData.pointers[0].id; - mCurrentRawPointerData.pointers[0].id = id; - mCurrentRawPointerData.idToIndex[id] = 0; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0)); + uint32_t id = last->rawPointerData.pointers[0].id; + current->rawPointerData.pointers[0].id = id; + current->rawPointerData.idToIndex[id] = 0; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0)); return; } @@ -5810,9 +6190,9 @@ void TouchInputMapper::assignPointerIds() { for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; lastPointerIndex++) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointers[currentPointerIndex]; + current->rawPointerData.pointers[currentPointerIndex]; const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointers[lastPointerIndex]; + last->rawPointerData.pointers[lastPointerIndex]; if (currentPointer.toolType == lastPointer.toolType) { int64_t deltaX = currentPointer.x - lastPointer.x; int64_t deltaY = currentPointer.y - lastPointer.y; @@ -5918,11 +6298,11 @@ void TouchInputMapper::assignPointerIds() { matchedCurrentBits.markBit(currentPointerIndex); matchedLastBits.markBit(lastPointerIndex); - uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id; - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); + uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id; + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); usedIdBits.markBit(id); #if DEBUG_POINTER_ASSIGNMENT @@ -5938,10 +6318,10 @@ void TouchInputMapper::assignPointerIds() { uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); uint32_t id = usedIdBits.markFirstUnmarkedBit(); - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - assigned: cur=%d, id=%d", @@ -6020,18 +6400,18 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) { mSingleTouchMotionAccumulator.process(rawEvent); } -void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { +void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { if (mTouchButtonAccumulator.isToolActive()) { - mCurrentRawPointerData.pointerCount = 1; - mCurrentRawPointerData.idToIndex[0] = 0; + outState->rawPointerData.pointerCount = 1; + outState->rawPointerData.idToIndex[0] = 0; bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); - mCurrentRawPointerData.markIdBit(0, isHovering); + outState->rawPointerData.markIdBit(0, isHovering); - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0]; + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0]; outPointer.id = 0; outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); @@ -6092,7 +6472,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { mMultiTouchMotionAccumulator.process(rawEvent); } -void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { +void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); size_t outCount = 0; BitSet32 newPointerIdBits; @@ -6113,7 +6493,7 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { break; // too many fingers! } - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount]; + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount]; outPointer.x = inSlot->getX(); outPointer.y = inSlot->getY(); outPointer.pressure = inSlot->getPressure(); @@ -6140,38 +6520,37 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. - if (*outHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); - int32_t id = -1; - if (trackingId >= 0) { - for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { - uint32_t n = idBits.clearFirstMarkedBit(); - if (mPointerTrackingIdMap[n] == trackingId) { - id = n; - } - } - - if (id < 0 && !mPointerIdBits.isFull()) { - id = mPointerIdBits.markFirstUnmarkedBit(); - mPointerTrackingIdMap[id] = trackingId; + mHavePointerIds = true; + int32_t trackingId = inSlot->getTrackingId(); + int32_t id = -1; + if (trackingId >= 0) { + for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { + uint32_t n = idBits.clearFirstMarkedBit(); + if (mPointerTrackingIdMap[n] == trackingId) { + id = n; } } - if (id < 0) { - *outHavePointerIds = false; - mCurrentRawPointerData.clearIdBits(); - newPointerIdBits.clear(); - } else { - outPointer.id = id; - mCurrentRawPointerData.idToIndex[id] = outCount; - mCurrentRawPointerData.markIdBit(id, isHovering); - newPointerIdBits.markBit(id); + + if (id < 0 && !mPointerIdBits.isFull()) { + id = mPointerIdBits.markFirstUnmarkedBit(); + mPointerTrackingIdMap[id] = trackingId; } } + if (id < 0) { + mHavePointerIds = false; + outState->rawPointerData.clearIdBits(); + newPointerIdBits.clear(); + } else { + outPointer.id = id; + outState->rawPointerData.idToIndex[id] = outCount; + outState->rawPointerData.markIdBit(id, isHovering); + newPointerIdBits.markBit(id); + } outCount += 1; } - mCurrentRawPointerData.pointerCount = outCount; + outState->rawPointerData.pointerCount = outCount; mPointerIdBits = newPointerIdBits; mMultiTouchMotionAccumulator.finishSync(); @@ -6215,6 +6594,77 @@ bool MultiTouchInputMapper::hasStylus() const { || mTouchButtonAccumulator.hasStylus(); } +// --- ExternalStylusInputMapper + +ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) : + InputMapper(device) { + +} + +uint32_t ExternalStylusInputMapper::getSources() { + return AINPUT_SOURCE_STYLUS; +} + +void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, + 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); +} + +void ExternalStylusInputMapper::dump(String8& dump) { + dump.append(INDENT2 "External Stylus Input Mapper:\n"); + dump.append(INDENT3 "Raw Stylus Axes:\n"); + dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure"); + dump.append(INDENT3 "Stylus State:\n"); + dumpStylusState(dump, mStylusState); +} + +void ExternalStylusInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis); + mTouchButtonAccumulator.configure(getDevice()); +} + +void ExternalStylusInputMapper::reset(nsecs_t when) { + InputDevice* device = getDevice(); + mSingleTouchMotionAccumulator.reset(device); + mTouchButtonAccumulator.reset(device); + InputMapper::reset(when); +} + +void ExternalStylusInputMapper::process(const RawEvent* rawEvent) { + mSingleTouchMotionAccumulator.process(rawEvent); + mTouchButtonAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void ExternalStylusInputMapper::sync(nsecs_t when) { + mStylusState.clear(); + + mStylusState.when = when; + + mStylusState.toolType = mTouchButtonAccumulator.getToolType(); + if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + } + + int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); + if (mRawPressureAxis.valid) { + mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue; + } else if (mTouchButtonAccumulator.isToolActive()) { + mStylusState.pressure = 1.0f; + } else { + mStylusState.pressure = 0.0f; + } + + mStylusState.buttons = mTouchButtonAccumulator.getButtonState(); + + mContext->dispatchExternalStylusState(mStylusState); +} + // --- JoystickInputMapper --- @@ -6538,7 +6988,7 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { uint32_t policyFlags = 0; NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0); getListener()->notifyMotion(&args); } diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index 34f20af..7cb4680 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -139,7 +139,10 @@ struct InputReaderConfiguration { CHANGE_DEVICE_ALIAS = 1 << 5, // The location calibration matrix changed. - TOUCH_AFFINE_TRANSFORMATION = 1 << 6, + CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6, + + // The presence of an external stylus has changed. + CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7, // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, @@ -371,6 +374,31 @@ public: virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0; }; +struct StylusState { + /* Time the stylus event was received. */ + nsecs_t when; + /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */ + float pressure; + /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */ + uint32_t buttons; + /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */ + int32_t toolType; + + void copyFrom(const StylusState& other) { + when = other.when; + pressure = other.pressure; + buttons = other.buttons; + toolType = other.toolType; + } + + void clear() { + when = LLONG_MAX; + pressure = 0.f; + buttons = 0; + toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + } +}; + /* Internal interface used by individual input devices to access global input device state * and parameters maintained by the input reader. @@ -392,6 +420,9 @@ public: virtual void requestTimeoutAtTime(nsecs_t when) = 0; virtual int32_t bumpGeneration() = 0; + virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) = 0; + virtual void dispatchExternalStylusState(const StylusState& outState) = 0; + virtual InputReaderPolicyInterface* getPolicy() = 0; virtual InputListenerInterface* getListener() = 0; virtual EventHubInterface* getEventHub() = 0; @@ -458,6 +489,8 @@ protected: virtual void fadePointer(); virtual void requestTimeoutAtTime(nsecs_t when); virtual int32_t bumpGeneration(); + virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices); + virtual void dispatchExternalStylusState(const StylusState& outState); virtual InputReaderPolicyInterface* getPolicy(); virtual InputListenerInterface* getListener(); virtual EventHubInterface* getEventHub(); @@ -496,6 +529,10 @@ private: void updateGlobalMetaStateLocked(); int32_t getGlobalMetaStateLocked(); + void notifyExternalStylusPresenceChanged(); + void getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices); + void dispatchExternalStylusState(const StylusState& state); + void fadePointerLocked(); int32_t mGeneration; @@ -555,6 +592,9 @@ public: inline bool isExternal() { return mIsExternal; } inline void setExternal(bool external) { mIsExternal = external; } + inline void setMic(bool hasMic) { mHasMic = hasMic; } + inline bool hasMic() const { return mHasMic; } + inline bool isIgnored() { return mMappers.isEmpty(); } void dump(String8& dump); @@ -563,6 +603,7 @@ public: void reset(nsecs_t when); void process(const RawEvent* rawEvents, size_t count); void timeoutExpired(nsecs_t when); + void updateExternalStylusState(const StylusState& state); void getDeviceInfo(InputDeviceInfo* outDeviceInfo); int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); @@ -618,6 +659,7 @@ private: uint32_t mSources; bool mIsExternal; + bool mHasMic; bool mDropUntilNextSync; typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); @@ -831,9 +873,21 @@ struct CookedPointerData { return pointerCoords[idToIndex[id]]; } - inline bool isHovering(uint32_t pointerIndex) { + inline PointerCoords& editPointerCoordsWithId(uint32_t id) { + return pointerCoords[idToIndex[id]]; + } + + inline PointerProperties& editPointerPropertiesWithId(uint32_t id) { + return pointerProperties[idToIndex[id]]; + } + + inline bool isHovering(uint32_t pointerIndex) const { return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); } + + inline bool isTouching(uint32_t pointerIndex) const { + return touchingIdBits.hasBit(pointerProperties[pointerIndex].id); + } }; @@ -978,6 +1032,8 @@ public: virtual int32_t getMetaState(); + virtual void updateExternalStylusState(const StylusState& state); + virtual void fadePointer(); protected: @@ -989,6 +1045,7 @@ protected: static void dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name); + static void dumpStylusState(String8& dump, const StylusState& state); }; @@ -1195,6 +1252,7 @@ public: virtual void fadePointer(); virtual void cancelTouch(nsecs_t when); virtual void timeoutExpired(nsecs_t when); + virtual void updateExternalStylusState(const StylusState& state); protected: CursorButtonAccumulator mCursorButtonAccumulator; @@ -1334,36 +1392,86 @@ protected: // Affine location transformation/calibration struct TouchAffineTransformation mAffineTransform; - // Raw pointer axis information from the driver. RawPointerAxes mRawPointerAxes; - // Raw pointer sample data. - RawPointerData mCurrentRawPointerData; - RawPointerData mLastRawPointerData; + struct RawState { + nsecs_t when; + + // Raw pointer sample data. + RawPointerData rawPointerData; + + int32_t buttonState; + + // Scroll state. + int32_t rawVScroll; + int32_t rawHScroll; + + void copyFrom(const RawState& other) { + when = other.when; + rawPointerData.copyFrom(other.rawPointerData); + buttonState = other.buttonState; + rawVScroll = other.rawVScroll; + rawHScroll = other.rawHScroll; + } + + void clear() { + when = 0; + rawPointerData.clear(); + buttonState = 0; + rawVScroll = 0; + rawHScroll = 0; + } + }; + + struct CookedState { + // Cooked pointer sample data. + CookedPointerData cookedPointerData; - // Cooked pointer sample data. - CookedPointerData mCurrentCookedPointerData; - CookedPointerData mLastCookedPointerData; + // Id bits used to differentiate fingers, stylus and mouse tools. + BitSet32 fingerIdBits; + BitSet32 stylusIdBits; + BitSet32 mouseIdBits; - // Button state. - int32_t mCurrentButtonState; - int32_t mLastButtonState; + int32_t buttonState; - // Scroll state. - int32_t mCurrentRawVScroll; - int32_t mCurrentRawHScroll; + void copyFrom(const CookedState& other) { + cookedPointerData.copyFrom(other.cookedPointerData); + fingerIdBits = other.fingerIdBits; + stylusIdBits = other.stylusIdBits; + mouseIdBits = other.mouseIdBits; + buttonState = other.buttonState; + } - // Id bits used to differentiate fingers, stylus and mouse tools. - BitSet32 mCurrentFingerIdBits; // finger or unknown - BitSet32 mLastFingerIdBits; - BitSet32 mCurrentStylusIdBits; // stylus or eraser - BitSet32 mLastStylusIdBits; - BitSet32 mCurrentMouseIdBits; // mouse or lens - BitSet32 mLastMouseIdBits; + void clear() { + cookedPointerData.clear(); + fingerIdBits.clear(); + stylusIdBits.clear(); + mouseIdBits.clear(); + buttonState = 0; + } + }; + + Vector<RawState> mRawStatesPending; + RawState mCurrentRawState; + CookedState mCurrentCookedState; + RawState mLastRawState; + CookedState mLastCookedState; + + // State provided by an external stylus + StylusState mExternalStylusState; + int64_t mExternalStylusId; + nsecs_t mExternalStylusFusionTimeout; + bool mExternalStylusDataPending; // True if we sent a HOVER_ENTER event. bool mSentHoverEnter; + // Have we assigned pointer IDs for this stream + bool mHavePointerIds; + + // Is the current stream of direct touch events aborted + bool mCurrentMotionAborted; + // The time the primary pointer last went down. nsecs_t mDownTime; @@ -1383,11 +1491,13 @@ protected: virtual void parseCalibration(); virtual void resolveCalibration(); virtual void dumpCalibration(String8& dump); + virtual void updateAffineTransformation(); virtual void dumpAffineTransformation(String8& dump); + virtual void resolveExternalStylusPresence(); virtual bool hasStylus() const = 0; - virtual void updateAffineTransformation(); + virtual bool hasExternalStylus() const; - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0; + virtual void syncTouch(nsecs_t when, RawState* outState) = 0; private: // The current viewport. @@ -1433,6 +1543,8 @@ private: float mTiltYCenter; float mTiltYScale; + bool mExternalStylusConnected; + // Oriented motion ranges for input device info. struct OrientedRanges { InputDeviceInfo::MotionRange x; @@ -1675,16 +1787,25 @@ private: VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; + void resetExternalStylus(); + void clearStylusDataPendingFlags(); + void sync(nsecs_t when); bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); + void processRawTouches(bool timeout); + void cookAndDispatch(nsecs_t when); void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, int32_t keyEventFlags); void dispatchTouches(nsecs_t when, uint32_t policyFlags); void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); + void dispatchButtonRelease(nsecs_t when, uint32_t policyFlags); + void dispatchButtonPress(nsecs_t when, uint32_t policyFlags); + const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData); void cookPointerData(); + void abortTouches(nsecs_t when, uint32_t policyFlags); void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); void abortPointerUsage(nsecs_t when, uint32_t policyFlags); @@ -1705,13 +1826,17 @@ private: bool down, bool hovering); void abortPointerSimple(nsecs_t when, uint32_t policyFlags); + bool assignExternalStylusId(const RawState& state, bool timeout); + void applyExternalStylusButtonState(nsecs_t when); + void applyExternalStylusTouchState(nsecs_t when); + // Dispatches a motion event. // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the // method will take care of setting the index and transmuting the action to DOWN or UP // it is the first / last pointer to go down / up. void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, + int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); @@ -1726,7 +1851,7 @@ private: bool isPointInsideSurface(int32_t x, int32_t y); const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); - void assignPointerIds(); + static void assignPointerIds(const RawState* last, RawState* current); }; @@ -1739,7 +1864,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); + virtual void syncTouch(nsecs_t when, RawState* outState); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; @@ -1757,7 +1882,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); + virtual void syncTouch(nsecs_t when, RawState* outState); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; @@ -1769,6 +1894,27 @@ private: int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; }; +class ExternalStylusInputMapper : public InputMapper { +public: + ExternalStylusInputMapper(InputDevice* device); + virtual ~ExternalStylusInputMapper() = default; + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + virtual void sync(nsecs_t when); + +private: + SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; + RawAbsoluteAxisInfo mRawPressureAxis; + TouchButtonAccumulator mTouchButtonAccumulator; + + StylusState mStylusState; +}; + class JoystickInputMapper : public InputMapper { public: diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk new file mode 100644 index 0000000..b828175 --- /dev/null +++ b/services/inputflinger/host/Android.mk @@ -0,0 +1,62 @@ +# Copyright (C) 2015 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_CLANG := true + +LOCAL_SRC_FILES:= \ + InputFlinger.cpp \ + InputDriver.cpp \ + InputHost.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libcrypto \ + libcutils \ + libinput \ + liblog \ + libutils \ + libhardware + + +# TODO: Move inputflinger to its own process and mark it hidden +#LOCAL_CFLAGS += -fvisibility=hidden + +LOCAL_CFLAGS += -Wno-unused-parameter + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) + +LOCAL_MODULE := libinputflingerhost + +include $(BUILD_SHARED_LIBRARY) + +######################################################################## +# build input flinger executable +include $(CLEAR_VARS) + +LOCAL_CLANG := true + +LOCAL_SRC_FILES:= \ + main.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libinputflingerhost \ + libutils + +LOCAL_MODULE := inputflinger + +include $(BUILD_EXECUTABLE) diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp new file mode 100644 index 0000000..630a596 --- /dev/null +++ b/services/inputflinger/host/InputDriver.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2015 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. + */ + +#include <stdint.h> +#include <sys/types.h> + +#define LOG_TAG "InputDriver" + +#define LOG_NDEBUG 0 + +#include "InputDriver.h" +#include "InputHost.h" + +#include <hardware/input.h> +#include <utils/Log.h> +#include <utils/String8.h> + +#define INDENT2 " " + +namespace android { + +static input_host_callbacks_t kCallbacks = { + .create_device_identifier = create_device_identifier, + .create_device_definition = create_device_definition, + .create_input_report_definition = create_input_report_definition, + .create_output_report_definition = create_output_report_definition, + .input_device_definition_add_report = input_device_definition_add_report, + .input_report_definition_add_collection = input_report_definition_add_collection, + .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int, + .input_report_definition_declare_usages_bool = input_report_definition_declare_usages_bool, + .register_device = register_device, + .input_allocate_report = input_allocate_report, + .input_report_set_usage_int = input_report_set_usage_int, + .input_report_set_usage_bool = input_report_set_usage_bool, + .report_event = report_event, + .input_get_device_property_map = input_get_device_property_map, + .input_get_device_property = input_get_device_property, + .input_get_property_key = input_get_property_key, + .input_get_property_value = input_get_property_value, + .input_free_device_property = input_free_device_property, + .input_free_device_property_map = input_free_device_property_map, +}; + +InputDriver::InputDriver(const char* name) : mName(String8(name)) { + const hw_module_t* module; + int err = input_open(&module, name); + LOG_ALWAYS_FATAL_IF(err != 0, "Input module %s not found", name); + mHal = reinterpret_cast<const input_module_t*>(module); +} + +void InputDriver::init(InputHostInterface* host) { + mHal->init(mHal, static_cast<input_host_t*>(host), kCallbacks); +} + +void InputDriver::dump(String8& result) { + result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string()); +} + + +// HAL wrapper functions + +input_device_identifier_t* create_device_identifier(input_host_t* host, + const char* name, int32_t product_id, int32_t vendor_id, + input_bus_t bus, const char* unique_id) { + return nullptr; +} + +input_device_definition_t* create_device_definition(input_host_t* host) { + return nullptr; +} + +input_report_definition_t* create_input_report_definition(input_host_t* host) { + return nullptr; +} + +input_report_definition_t* create_output_report_definition(input_host_t* host) { + return nullptr; +} + +void input_device_definition_add_report(input_host_t* host, + input_device_definition_t* d, input_report_definition_t* r) { } + +void input_report_definition_add_collection(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, int32_t arity) { } + +void input_report_definition_declare_usage_int(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t usage, int32_t min, int32_t max, float resolution) { } + +void input_report_definition_declare_usages_bool(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t* usage, size_t usage_count) { } + + +input_device_handle_t* register_device(input_host_t* host, + input_device_identifier_t* id, input_device_definition_t* d) { + return nullptr; +} + +input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) { + return nullptr; +} +void input_report_set_usage_int(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { } + +void input_report_set_usage_bool(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { } + +void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { } + +input_property_map_t* input_get_device_property_map(input_host_t* host, + input_device_identifier_t* id) { + return nullptr; +} + +input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map, + const char* key) { + return nullptr; +} + +const char* input_get_property_key(input_host_t* host, input_property_t* property) { + return nullptr; +} + +const char* input_get_property_value(input_host_t* host, input_property_t* property) { + return nullptr; +} + +void input_free_device_property(input_host_t* host, input_property_t* property) { } + +void input_free_device_property_map(input_host_t* host, input_property_map_t* map) { } + +} // namespace android diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h new file mode 100644 index 0000000..7734ac2 --- /dev/null +++ b/services/inputflinger/host/InputDriver.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef ANDROID_INPUT_DRIVER_H +#define ANDROID_INPUT_DRIVER_H + +#include <stdint.h> +#include <sys/types.h> + +#include "InputHost.h" + +#include <hardware/input.h> +#include <utils/RefBase.h> +#include <utils/String8.h> + +namespace android { + +class InputHostInterface; + +class InputDriverInterface : public virtual RefBase { +protected: + InputDriverInterface() = default; + virtual ~InputDriverInterface() = default; + +public: + virtual void init(InputHostInterface* host) = 0; + + virtual void dump(String8& result) = 0; +}; + +class InputDriver : public InputDriverInterface { +public: + InputDriver(const char* name); + virtual ~InputDriver() = default; + + virtual void init(InputHostInterface* host) override; + + virtual void dump(String8& result) override; + +private: + String8 mName; + const input_module_t* mHal; +}; + + +extern "C" { + +input_device_identifier_t* create_device_identifier(input_host_t* host, + const char* name, int32_t product_id, int32_t vendor_id, + input_bus_t bus, const char* unique_id); + +input_device_definition_t* create_device_definition(input_host_t* host); + +input_report_definition_t* create_input_report_definition(input_host_t* host); + +input_report_definition_t* create_output_report_definition(input_host_t* host); + +void input_device_definition_add_report(input_host_t* host, + input_device_definition_t* d, input_report_definition_t* r); + +void input_report_definition_add_collection(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, int32_t arity); + +void input_report_definition_declare_usage_int(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t usage, int32_t min, int32_t max, float resolution); + +void input_report_definition_declare_usages_bool(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t* usage, size_t usage_count); + + +input_device_handle_t* register_device(input_host_t* host, + input_device_identifier_t* id, input_device_definition_t* d); + +void unregister_device(input_host_t* host, input_device_handle_t* handle); + +input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r); + +void input_report_set_usage_int(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index); + +void input_report_set_usage_bool(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index); + +void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report); + +input_property_map_t* input_get_device_property_map(input_host_t* host, + input_device_identifier_t* id); + +input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map, + const char* key); + +const char* input_get_property_key(input_host_t* host, input_property_t* property); + +const char* input_get_property_value(input_host_t* host, input_property_t* property); + +void input_free_device_property(input_host_t* host, input_property_t* property); + +void input_free_device_property_map(input_host_t* host, input_property_map_t* map); +} + +} // namespace android +#endif // ANDROID_INPUT_DRIVER_H diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp new file mode 100644 index 0000000..859c3b8 --- /dev/null +++ b/services/inputflinger/host/InputFlinger.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2013 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 "InputFlinger" + + +#include <stdint.h> +#include <unistd.h> + +#include <sys/types.h> + +#include "InputFlinger.h" +#include "InputDriver.h" + +#include <binder/IPCThreadState.h> +#include <binder/PermissionCache.h> +#include <hardware/input.h> +#include <cutils/log.h> +#include <private/android_filesystem_config.h> + +namespace android { + +const String16 sAccessInputFlingerPermission("android.permission.ACCESS_INPUT_FLINGER"); +const String16 sDumpPermission("android.permission.DUMP"); + + +InputFlinger::InputFlinger() : + BnInputFlinger() { + ALOGI("InputFlinger is starting"); + mHost = new InputHost(); + mHost->registerInputDriver(new InputDriver(INPUT_INSTANCE_EVDEV)); +} + +InputFlinger::~InputFlinger() { +} + +status_t InputFlinger::dump(int fd, const Vector<String16>& args) { + String8 result; + const IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) + && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) { + result.appendFormat("Permission Denial: " + "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); + } else { + dumpInternal(result); + } + write(fd, result.string(), result.size()); + return OK; +} + +void InputFlinger::dumpInternal(String8& result) { + result.append("INPUT FLINGER (dumpsys inputflinger)\n"); + mHost->dump(result); +} + +}; // namespace android diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h new file mode 100644 index 0000000..39e69e5 --- /dev/null +++ b/services/inputflinger/host/InputFlinger.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef ANDROID_INPUT_FLINGER_H +#define ANDROID_INPUT_FLINGER_H + +#include <stdint.h> +#include <sys/types.h> + +#include "InputHost.h" + +#include <cutils/compiler.h> +#include <input/IInputFlinger.h> +#include <utils/String8.h> +#include <utils/String16.h> +#include <utils/StrongPointer.h> + +namespace android { + +class InputFlinger : public BnInputFlinger { +public: + static char const* getServiceName() ANDROID_API { + return "inputflinger"; + } + + InputFlinger() ANDROID_API; + + virtual status_t dump(int fd, const Vector<String16>& args); + +private: + virtual ~InputFlinger(); + + void dumpInternal(String8& result); + + sp<InputHostInterface> mHost; +}; + +} // namespace android + +#endif // ANDROID_INPUT_FLINGER_H diff --git a/services/inputflinger/host/InputHost.cpp b/services/inputflinger/host/InputHost.cpp new file mode 100644 index 0000000..51d3e6b --- /dev/null +++ b/services/inputflinger/host/InputHost.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 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. + */ + +#include <vector> + +#include "InputDriver.h" +#include "InputHost.h" + +#include <utils/Log.h> +#include <utils/String8.h> + +#define INDENT " " + +namespace android { + +void InputHost::registerInputDriver(InputDriverInterface* driver) { + LOG_ALWAYS_FATAL_IF(driver == nullptr, "Cannot register a nullptr as an InputDriver!"); + driver->init(this); + mDrivers.push_back(driver); +} + +void InputHost::dump(String8& result) { + result.append(INDENT "Input Drivers:\n"); + for (size_t i = 0; i < mDrivers.size(); i++) { + mDrivers[i]->dump(result); + } +} + +} // namespace android diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h new file mode 100644 index 0000000..42a66e0 --- /dev/null +++ b/services/inputflinger/host/InputHost.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef ANDROID_INPUT_HOST_H +#define ANDROID_INPUT_HOST_H + +#include <vector> + +#include <hardware/input.h> +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <utils/StrongPointer.h> + +#include "InputDriver.h" + +// Declare a concrete type for the HAL +struct input_host { +}; + +namespace android { + +class InputDriverInterface; + +class InputHostInterface : public input_host_t, public virtual RefBase { +protected: + InputHostInterface() = default; + virtual ~InputHostInterface() = default; + +public: + + virtual void registerInputDriver(InputDriverInterface* driver) = 0; + + virtual void dump(String8& result) = 0; +}; + +class InputHost : public InputHostInterface { +public: + InputHost() = default; + + virtual void registerInputDriver(InputDriverInterface* driver) override; + + virtual void dump(String8& result) override; + +private: + std::vector<sp<InputDriverInterface>> mDrivers; +}; + +} // namespace android +#endif // ANDRIOD_INPUT_HOST_H diff --git a/services/inputflinger/host/main.cpp b/services/inputflinger/host/main.cpp new file mode 100644 index 0000000..0a517cc --- /dev/null +++ b/services/inputflinger/host/main.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 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. + */ + +#include <binder/BinderService.h> +#include "InputFlinger.h" + +using namespace android; + +int main(int, char**) { + ProcessState::self()->setThreadPoolMaxThreadCount(4); + BinderService<InputFlinger>::publishAndJoinThreadPool(true); + return 0; +} diff --git a/services/inputflinger/tests/Android.mk b/services/inputflinger/tests/Android.mk index 0742a08..4c43392 100644 --- a/services/inputflinger/tests/Android.mk +++ b/services/inputflinger/tests/Android.mk @@ -10,7 +10,6 @@ test_src_files := \ shared_libraries := \ libcutils \ liblog \ - libandroidfw \ libutils \ libhardware \ libhardware_legacy \ @@ -24,7 +23,7 @@ c_includes := \ external/skia/include/core -module_tags := eng tests +module_tags := tests $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 9b68986..2d8eaef 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -150,7 +150,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects undefined motion actions. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -161,7 +161,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects pointer down with invalid index. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -171,7 +171,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -182,7 +182,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects pointer up with invalid index. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -192,7 +192,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -202,7 +202,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with invalid number of pointers. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -211,7 +211,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { << "Should reject motion events with 0 pointers."; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -222,7 +222,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with invalid pointer ids. pointerProperties[0].id = -1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -232,7 +232,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { pointerProperties[0].id = MAX_POINTER_ID + 1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -244,7 +244,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { pointerProperties[0].id = 1; pointerProperties[1].id = 1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 40f51b6..f34b810 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -777,6 +777,14 @@ private: virtual int32_t bumpGeneration() { return ++mGeneration; } + + virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) { + + } + + virtual void dispatchExternalStylusState(const StylusState&) { + + } }; diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 80845a2..dd1bccf 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -79,16 +79,17 @@ void SensorDevice::dump(String8& result) sensor_t const* list; ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list); - result.appendFormat("halVersion %d\n", getHalDeviceVersion()); + result.appendFormat("halVersion 0x%08x\n", getHalDeviceVersion()); result.appendFormat("%d h/w sensors:\n", int(count)); Mutex::Autolock _l(mLock); for (size_t i=0 ; i<size_t(count) ; i++) { const Info& info = mActivationCount.valueFor(list[i].handle); + if (info.batchParams.isEmpty()) continue; result.appendFormat("handle=0x%08x, active-count=%zu, batch_period(ms)={ ", list[i].handle, info.batchParams.size()); for (size_t j = 0; j < info.batchParams.size(); j++) { - BatchParams params = info.batchParams.valueAt(j); + const BatchParams& params = info.batchParams.valueAt(j); result.appendFormat("%4.1f%s", params.batchDelay / 1e6f, j < info.batchParams.size() - 1 ? ", " : ""); } @@ -147,8 +148,12 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) if (enabled) { ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident)); + if (isClientDisabledLocked(ident)) { + return INVALID_OPERATION; + } + if (info.batchParams.indexOfKey(ident) >= 0) { - if (info.batchParams.size() == 1) { + if (info.numActiveClients() == 1) { // This is the first connection, we need to activate the underlying h/w sensor. actuateHardware = true; } @@ -160,7 +165,7 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident)); if (info.removeBatchParamsForIdent(ident) >= 0) { - if (info.batchParams.size() == 0) { + if (info.numActiveClients() == 0) { // This is the last connection, we need to de-activate the underlying h/w sensor. actuateHardware = true; } else { @@ -181,10 +186,15 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) } else { // sensor wasn't enabled for this ident } + + if (isClientDisabledLocked(ident)) { + return NO_ERROR; + } } if (actuateHardware) { - ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, enabled); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, + enabled); err = mSensorDevice->activate( reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), handle, enabled); ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle, @@ -197,7 +207,7 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) } // On older devices which do not support batch, call setDelay(). - if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.batchParams.size() > 0) { + if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) { ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle, info.bestBatchParams.batchDelay); mSensorDevice->setDelay( @@ -279,6 +289,7 @@ status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodN samplingPeriodNs = MINIMUM_EVENTS_PERIOD; } Mutex::Autolock _l(mLock); + if (isClientDisabledLocked(ident)) return INVALID_OPERATION; Info& info( mActivationCount.editValueFor(handle) ); // If the underlying sensor is NOT in continuous mode, setDelay() should return an error. // Calling setDelay() in batch mode is an invalid operation. @@ -298,7 +309,6 @@ status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodN int SensorDevice::getHalDeviceVersion() const { if (!mSensorDevice) return -1; - return mSensorDevice->common.version; } @@ -306,12 +316,110 @@ status_t SensorDevice::flush(void* ident, int handle) { if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) { return INVALID_OPERATION; } + if (isClientDisabled(ident)) return INVALID_OPERATION; ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle); return mSensorDevice->flush(mSensorDevice, handle); } +bool SensorDevice::isClientDisabled(void* ident) { + Mutex::Autolock _l(mLock); + return isClientDisabledLocked(ident); +} + +bool SensorDevice::isClientDisabledLocked(void* ident) { + return mDisabledClients.indexOf(ident) >= 0; +} + +void SensorDevice::enableAllSensors() { + Mutex::Autolock _l(mLock); + mDisabledClients.clear(); + const int halVersion = getHalDeviceVersion(); + for (size_t i = 0; i< mActivationCount.size(); ++i) { + Info& info = mActivationCount.editValueAt(i); + if (info.batchParams.isEmpty()) continue; + info.selectBatchParams(); + const int sensor_handle = mActivationCount.keyAt(i); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ", + sensor_handle); + status_t err(NO_ERROR); + if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) { + err = mSensorDevice->batch(mSensorDevice, sensor_handle, + info.bestBatchParams.flags, info.bestBatchParams.batchDelay, + info.bestBatchParams.batchTimeout); + ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err)); + } + + if (err == NO_ERROR) { + err = mSensorDevice->activate( + reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice), + sensor_handle, 1); + ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err)); + } + + if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) { + err = mSensorDevice->setDelay( + reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice), + sensor_handle, info.bestBatchParams.batchDelay); + ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err)); + } + } +} + +void SensorDevice::disableAllSensors() { + Mutex::Autolock _l(mLock); + for (size_t i = 0; i< mActivationCount.size(); ++i) { + const Info& info = mActivationCount.valueAt(i); + // Check if this sensor has been activated previously and disable it. + if (info.batchParams.size() > 0) { + const int sensor_handle = mActivationCount.keyAt(i); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ", + sensor_handle); + mSensorDevice->activate( + reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), + sensor_handle, 0); + // Add all the connections that were registered for this sensor to the disabled + // clients list. + for (size_t j = 0; j < info.batchParams.size(); ++j) { + mDisabledClients.add(info.batchParams.keyAt(j)); + } + } + } +} + +status_t SensorDevice::injectSensorData(const sensors_event_t *injected_sensor_event) { + ALOGD_IF(DEBUG_CONNECTIONS, + "sensor_event handle=%d ts=%lld data=%.2f, %.2f, %.2f %.2f %.2f %.2f", + injected_sensor_event->sensor, + injected_sensor_event->timestamp, injected_sensor_event->data[0], + injected_sensor_event->data[1], injected_sensor_event->data[2], + injected_sensor_event->data[3], injected_sensor_event->data[4], + injected_sensor_event->data[5]); + if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) { + return INVALID_OPERATION; + } + return mSensorDevice->inject_sensor_data(mSensorDevice, injected_sensor_event); +} + +status_t SensorDevice::setMode(uint32_t mode) { + if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) { + return INVALID_OPERATION; + } + return mSensorModule->set_operation_mode(mode); +} + // --------------------------------------------------------------------------- +int SensorDevice::Info::numActiveClients() { + SensorDevice& device(SensorDevice::getInstance()); + int num = 0; + for (size_t i = 0; i < batchParams.size(); ++i) { + if (!device.isClientDisabledLocked(batchParams.keyAt(i))) { + ++num; + } + } + return num; +} + status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { @@ -329,19 +437,16 @@ status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags, } void SensorDevice::Info::selectBatchParams() { - BatchParams bestParams(-1, -1, -1); - - if (batchParams.size() > 0) { - BatchParams params = batchParams.valueAt(0); - bestParams = params; - } + BatchParams bestParams(0, -1, -1); + SensorDevice& device(SensorDevice::getInstance()); - for (size_t i = 1; i < batchParams.size(); ++i) { + for (size_t i = 0; i < batchParams.size(); ++i) { + if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue; BatchParams params = batchParams.valueAt(i); - if (params.batchDelay < bestParams.batchDelay) { + if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) { bestParams.batchDelay = params.batchDelay; } - if (params.batchTimeout < bestParams.batchTimeout) { + if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) { bestParams.batchTimeout = params.batchTimeout; } } diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index 761b48c..c484849 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -42,6 +42,7 @@ class SensorDevice : public Singleton<SensorDevice> { // Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from // batch call. For continous mode clients, maxBatchReportLatency is set to zero. struct BatchParams { + // TODO: Get rid of flags parameter everywhere. int flags; nsecs_t batchDelay, batchTimeout; BatchParams() : flags(0), batchDelay(0), batchTimeout(0) {} @@ -65,7 +66,7 @@ class SensorDevice : public Singleton<SensorDevice> { // requested by the client. KeyedVector<void*, BatchParams> batchParams; - Info() : bestBatchParams(-1, -1, -1) {} + Info() : bestBatchParams(0, -1, -1) {} // Sets batch parameters for this ident. Returns error if this ident is not already present // in the KeyedVector above. status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs, @@ -75,10 +76,17 @@ class SensorDevice : public Singleton<SensorDevice> { // Removes batchParams for an ident and re-computes bestBatchParams. Returns the index of // the removed ident. If index >=0, ident is present and successfully removed. ssize_t removeBatchParamsForIdent(void* ident); + + int numActiveClients(); }; DefaultKeyedVector<int, Info> mActivationCount; + // Use this vector to determine which client is activated or deactivated. + SortedVector<void *> mDisabledClients; SensorDevice(); + + bool isClientDisabled(void* ident); + bool isClientDisabledLocked(void* ident); public: ssize_t getSensorList(sensor_t const** list); status_t initCheck() const; @@ -90,7 +98,11 @@ public: // Call batch with timeout zero instead of calling setDelay() for newer devices. status_t setDelay(void* ident, int handle, int64_t ns); status_t flush(void* ident, int handle); + status_t setMode(uint32_t mode); + void disableAllSensors(); + void enableAllSensors(); void autoDisable(void *ident, int handle); + status_t injectSensorData(const sensors_event_t *event); void dump(String8& result); }; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index a857366..40b21a9 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -31,6 +31,7 @@ #include <utils/Singleton.h> #include <utils/String16.h> +#include <binder/AppOpsManager.h> #include <binder/BinderService.h> #include <binder/IServiceManager.h> #include <binder/PermissionCache.h> @@ -63,7 +64,9 @@ namespace android { * */ -const char* SensorService::WAKE_LOCK_NAME = "SensorService"; +const char* SensorService::WAKE_LOCK_NAME = "SensorService_wakelock"; +// Permissions. +static const String16 sDump("android.permission.DUMP"); SensorService::SensorService() : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED), @@ -74,7 +77,6 @@ SensorService::SensorService() void SensorService::onFirstRef() { ALOGD("nuSensorService starting..."); - SensorDevice& dev(SensorDevice::getInstance()); if (dev.initCheck() == NO_ERROR) { @@ -82,7 +84,7 @@ void SensorService::onFirstRef() ssize_t count = dev.getSensorList(&list); if (count > 0) { ssize_t orientationIndex = -1; - bool hasGyro = false; + bool hasGyro = false, hasAccel = false, hasMag = false; uint32_t virtualSensorsNeeds = (1<<SENSOR_TYPE_GRAVITY) | (1<<SENSOR_TYPE_LINEAR_ACCELERATION) | @@ -92,6 +94,12 @@ void SensorService::onFirstRef() for (ssize_t i=0 ; i<count ; i++) { registerSensor( new HardwareSensor(list[i]) ); switch (list[i].type) { + case SENSOR_TYPE_ACCELEROMETER: + hasAccel = true; + break; + case SENSOR_TYPE_MAGNETIC_FIELD: + hasMag = true; + break; case SENSOR_TYPE_ORIENTATION: orientationIndex = i; break; @@ -115,7 +123,7 @@ void SensorService::onFirstRef() // build the sensor list returned to users mUserSensorList = mSensorList; - if (hasGyro) { + if (hasGyro && hasAccel && hasMag) { Sensor aSensor; // Add Android virtual sensors if they're not already @@ -154,7 +162,7 @@ void SensorService::onFirstRef() // Check if the device really supports batching by looking at the FIFO event // counts for each sensor. bool batchingSupported = false; - for (int i = 0; i < mSensorList.size(); ++i) { + for (size_t i = 0; i < mSensorList.size(); ++i) { if (mSensorList[i].getFifoMaxEventCount() > 0) { batchingSupported = true; break; @@ -190,10 +198,16 @@ void SensorService::onFirstRef() mSensorEventBuffer = new sensors_event_t[minBufferSize]; mSensorEventScratch = new sensors_event_t[minBufferSize]; mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize]; + mCurrentOperatingMode = NORMAL; + + mNextSensorRegIndex = 0; + for (int i = 0; i < SENSOR_REGISTRATIONS_BUF_SIZE; ++i) { + mLastNSensorRegistrations.push(); + } + mInitCheck = NO_ERROR; mAckReceiver = new SensorEventAckReceiver(this); mAckReceiver->run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY); - mInitCheck = NO_ERROR; run("SensorService", PRIORITY_URGENT_DISPLAY); } } @@ -210,7 +224,7 @@ Sensor SensorService::registerSensor(SensorInterface* s) // add to our handle->SensorInterface mapping mSensorMap.add(sensor.getHandle(), s); // create an entry in the mLastEventSeen array - mLastEventSeen.add(sensor.getHandle(), event); + mLastEventSeen.add(sensor.getHandle(), NULL); return sensor; } @@ -228,9 +242,7 @@ SensorService::~SensorService() delete mSensorMap.valueAt(i); } -static const String16 sDump("android.permission.DUMP"); - -status_t SensorService::dump(int fd, const Vector<String16>& /*args*/) +status_t SensorService::dump(int fd, const Vector<String16>& args) { String8 result; if (!PermissionCache::checkCallingPermission(sDump)) { @@ -239,116 +251,188 @@ status_t SensorService::dump(int fd, const Vector<String16>& /*args*/) IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); } else { + if (args.size() > 2) { + return INVALID_OPERATION; + } Mutex::Autolock _l(mLock); - result.append("Sensor List:\n"); - for (size_t i=0 ; i<mSensorList.size() ; i++) { - const Sensor& s(mSensorList[i]); - const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle())); - result.appendFormat( - "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |", - s.getName().string(), - s.getVendor().string(), - s.getVersion(), - s.getStringType().string(), - s.getHandle(), - s.getRequiredPermission().string(), - s.getType()); - - const int reportingMode = s.getReportingMode(); - if (reportingMode == AREPORTING_MODE_CONTINUOUS) { - result.append(" continuous | "); - } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) { - result.append(" on-change | "); - } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) { - result.append(" one-shot | "); - } else { - result.append(" special-trigger | "); + SensorDevice& dev(SensorDevice::getInstance()); + if (args.size() == 2 && args[0] == String16("restrict")) { + // If already in restricted mode. Ignore. + if (mCurrentOperatingMode == RESTRICTED) { + return status_t(NO_ERROR); } - - if (s.getMaxDelay() > 0) { - result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay()); - } else { - result.appendFormat("maxDelay=%dus |", s.getMaxDelay()); + // If in any mode other than normal, ignore. + if (mCurrentOperatingMode != NORMAL) { + return INVALID_OPERATION; } - - if (s.getMinDelay() > 0) { - result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay()); - } else { - result.appendFormat("minDelay=%dus |", s.getMinDelay()); + mCurrentOperatingMode = RESTRICTED; + dev.disableAllSensors(); + // Clear all pending flush connections for all active sensors. If one of the active + // connections has called flush() and the underlying sensor has been disabled before a + // flush complete event is returned, we need to remove the connection from this queue. + for (size_t i=0 ; i< mActiveSensors.size(); ++i) { + mActiveSensors.valueAt(i)->clearAllPendingFlushConnections(); } - - if (s.getFifoMaxEventCount() > 0) { - result.appendFormat("FifoMax=%d events | ", - s.getFifoMaxEventCount()); - } else { - result.append("no batching | "); + mWhiteListedPackage.setTo(String8(args[1])); + return status_t(NO_ERROR); + } else if (args.size() == 1 && args[0] == String16("enable")) { + // If currently in restricted mode, reset back to NORMAL mode else ignore. + if (mCurrentOperatingMode == RESTRICTED) { + mCurrentOperatingMode = NORMAL; + dev.enableAllSensors(); } - - if (s.isWakeUpSensor()) { - result.appendFormat("wakeUp | "); + if (mCurrentOperatingMode == DATA_INJECTION) { + resetToNormalModeLocked(); + } + mWhiteListedPackage.clear(); + return status_t(NO_ERROR); + } else if (args.size() == 2 && args[0] == String16("data_injection")) { + if (mCurrentOperatingMode == NORMAL) { + dev.disableAllSensors(); + status_t err = dev.setMode(DATA_INJECTION); + if (err == NO_ERROR) { + mCurrentOperatingMode = DATA_INJECTION; + } else { + // Re-enable sensors. + dev.enableAllSensors(); + } + mWhiteListedPackage.setTo(String8(args[1])); + return NO_ERROR; + } else if (mCurrentOperatingMode == DATA_INJECTION) { + // Already in DATA_INJECTION mode. Treat this as a no_op. + return NO_ERROR; } else { - result.appendFormat("non-wakeUp | "); + // Transition to data injection mode supported only from NORMAL mode. + return INVALID_OPERATION; } + } else if (mSensorList.size() == 0) { + result.append("No Sensors on the device\n"); + } else { + // Default dump the sensor list and debugging information. + result.append("Sensor List:\n"); + for (size_t i=0 ; i<mSensorList.size() ; i++) { + const Sensor& s(mSensorList[i]); + result.appendFormat( + "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |", + s.getName().string(), + s.getVendor().string(), + s.getVersion(), + s.getStringType().string(), + s.getHandle(), + s.getRequiredPermission().string(), + s.getType()); + + const int reportingMode = s.getReportingMode(); + if (reportingMode == AREPORTING_MODE_CONTINUOUS) { + result.append(" continuous | "); + } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) { + result.append(" on-change | "); + } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) { + result.append(" one-shot | "); + } else { + result.append(" special-trigger | "); + } - switch (s.getType()) { - case SENSOR_TYPE_ROTATION_VECTOR: - case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR: - result.appendFormat( - "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n", - e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.timestamp); - break; - case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: - case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: - result.appendFormat( - "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n", - e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.data[5], - e.timestamp); - break; - case SENSOR_TYPE_GAME_ROTATION_VECTOR: - result.appendFormat( - "last=<%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n", - e.data[0], e.data[1], e.data[2], e.data[3], e.timestamp); - break; - case SENSOR_TYPE_SIGNIFICANT_MOTION: - case SENSOR_TYPE_STEP_DETECTOR: - result.appendFormat( "last=<%f %" PRId64 ">\n", e.data[0], e.timestamp); - break; - case SENSOR_TYPE_STEP_COUNTER: - result.appendFormat( "last=<%" PRIu64 ", %" PRId64 ">\n", e.u64.step_counter, - e.timestamp); - break; - default: - // default to 3 values - result.appendFormat( - "last=<%5.1f,%5.1f,%5.1f, %" PRId64 ">\n", - e.data[0], e.data[1], e.data[2], e.timestamp); - break; + if (s.getMaxDelay() > 0) { + result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay()); + } else { + result.appendFormat("maxDelay=%dus |", s.getMaxDelay()); + } + + if (s.getMinDelay() > 0) { + result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay()); + } else { + result.appendFormat("minDelay=%dus |", s.getMinDelay()); + } + + if (s.getFifoMaxEventCount() > 0) { + result.appendFormat("FifoMax=%d events | ", + s.getFifoMaxEventCount()); + } else { + result.append("no batching | "); + } + + if (s.isWakeUpSensor()) { + result.appendFormat("wakeUp | "); + } else { + result.appendFormat("non-wakeUp | "); + } + + int bufIndex = mLastEventSeen.indexOfKey(s.getHandle()); + if (bufIndex >= 0) { + const CircularBuffer* buf = mLastEventSeen.valueAt(bufIndex); + if (buf != NULL && s.getRequiredPermission().isEmpty()) { + buf->printBuffer(result); + } else { + result.append("last=<> \n"); + } + } + result.append("\n"); + } + SensorFusion::getInstance().dump(result); + SensorDevice::getInstance().dump(result); + + result.append("Active sensors:\n"); + for (size_t i=0 ; i<mActiveSensors.size() ; i++) { + int handle = mActiveSensors.keyAt(i); + result.appendFormat("%s (handle=0x%08x, connections=%zu)\n", + getSensorName(handle).string(), + handle, + mActiveSensors.valueAt(i)->getNumConnections()); } - result.append("\n"); - } - SensorFusion::getInstance().dump(result); - SensorDevice::getInstance().dump(result); - - result.append("Active sensors:\n"); - for (size_t i=0 ; i<mActiveSensors.size() ; i++) { - int handle = mActiveSensors.keyAt(i); - result.appendFormat("%s (handle=0x%08x, connections=%zu)\n", - getSensorName(handle).string(), - handle, - mActiveSensors.valueAt(i)->getNumConnections()); - } - result.appendFormat("Socket Buffer size = %d events\n", - mSocketBufferSize/sizeof(sensors_event_t)); - result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : "not held"); - result.appendFormat("%zd active connections\n", mActiveConnections.size()); + result.appendFormat("Socket Buffer size = %d events\n", + mSocketBufferSize/sizeof(sensors_event_t)); + result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : + "not held"); + result.appendFormat("Mode :"); + switch(mCurrentOperatingMode) { + case NORMAL: + result.appendFormat(" NORMAL\n"); + break; + case RESTRICTED: + result.appendFormat(" RESTRICTED : %s\n", mWhiteListedPackage.string()); + break; + case DATA_INJECTION: + result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.string()); + } + result.appendFormat("%zd active connections\n", mActiveConnections.size()); - for (size_t i=0 ; i < mActiveConnections.size() ; i++) { - sp<SensorEventConnection> connection(mActiveConnections[i].promote()); - if (connection != 0) { - result.appendFormat("Connection Number: %zu \n", i); - connection->dump(result); + for (size_t i=0 ; i < mActiveConnections.size() ; i++) { + sp<SensorEventConnection> connection(mActiveConnections[i].promote()); + if (connection != 0) { + result.appendFormat("Connection Number: %zu \n", i); + connection->dump(result); + } } + + result.appendFormat("Previous Registrations:\n"); + // Log in the reverse chronological order. + int currentIndex = (mNextSensorRegIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % + SENSOR_REGISTRATIONS_BUF_SIZE; + const int startIndex = currentIndex; + do { + const SensorRegistrationInfo& reg_info = mLastNSensorRegistrations[currentIndex]; + if (SensorRegistrationInfo::isSentinel(reg_info)) { + // Ignore sentinel, proceed to next item. + currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % + SENSOR_REGISTRATIONS_BUF_SIZE; + continue; + } + if (reg_info.mActivated) { + result.appendFormat("%02d:%02d:%02d activated package=%s handle=0x%08x " + "samplingRate=%dus maxReportLatency=%dus\n", + reg_info.mHour, reg_info.mMin, reg_info.mSec, + reg_info.mPackageName.string(), reg_info.mSensorHandle, + reg_info.mSamplingRateUs, reg_info.mMaxReportLatencyUs); + } else { + result.appendFormat("%02d:%02d:%02d de-activated package=%s handle=0x%08x\n", + reg_info.mHour, reg_info.mMin, reg_info.mSec, + reg_info.mPackageName.string(), reg_info.mSensorHandle); + } + currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % + SENSOR_REGISTRATIONS_BUF_SIZE; + } while(startIndex != currentIndex); } } write(fd, result.string(), result.size()); @@ -371,8 +455,9 @@ void SensorService::cleanupAutoDisabledSensorLocked(const sp<SensorEventConnecti sensor->autoDisable(connection.get(), handle); cleanupWithoutDisableLocked(connection, handle); } + } - } + } } bool SensorService::threadLoop() @@ -554,7 +639,6 @@ void SensorService::setWakeLockAcquiredLocked(bool acquire) { } } - bool SensorService::isWakeLockAcquired() { Mutex::Autolock _l(mLock); return mWakeLockAcquired; @@ -577,19 +661,15 @@ bool SensorService::SensorEventAckReceiver::threadLoop() { void SensorService::recordLastValueLocked( const sensors_event_t* buffer, size_t count) { - const sensors_event_t* last = NULL; for (size_t i = 0; i < count; i++) { - const sensors_event_t* event = &buffer[i]; - if (event->type != SENSOR_TYPE_META_DATA) { - if (last && event->sensor != last->sensor) { - mLastEventSeen.editValueFor(last->sensor) = *last; + if (buffer[i].type != SENSOR_TYPE_META_DATA) { + CircularBuffer* &circular_buf = mLastEventSeen.editValueFor(buffer[i].sensor); + if (circular_buf == NULL) { + circular_buf = new CircularBuffer(buffer[i].type); } - last = event; + circular_buf->addEvent(buffer[i]); } } - if (last) { - mLastEventSeen.editValueFor(last->sensor) = *last; - } } void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count) @@ -630,12 +710,11 @@ bool SensorService::isWakeUpSensorEvent(const sensors_event_t& event) const { return sensor != NULL && sensor->getSensor().isWakeUpSensor(); } - SensorService::SensorRecord * SensorService::getSensorRecord(int handle) { return mActiveSensors.valueFor(handle); } -Vector<Sensor> SensorService::getSensorList() +Vector<Sensor> SensorService::getSensorList(const String16& opPackageName) { char value[PROPERTY_VALUE_MAX]; property_get("debug.sensors", value, "0"); @@ -644,24 +723,65 @@ Vector<Sensor> SensorService::getSensorList() Vector<Sensor> accessibleSensorList; for (size_t i = 0; i < initialSensorList.size(); i++) { Sensor sensor = initialSensorList[i]; - if (canAccessSensor(sensor)) { + if (canAccessSensor(sensor, "getSensorList", opPackageName)) { accessibleSensorList.add(sensor); } else { - ALOGI("Skipped sensor %s because it requires permission %s", + ALOGI("Skipped sensor %s because it requires permission %s and app op %d", sensor.getName().string(), - sensor.getRequiredPermission().string()); + sensor.getRequiredPermission().string(), + sensor.getRequiredAppOp()); } } return accessibleSensorList; } -sp<ISensorEventConnection> SensorService::createSensorEventConnection() -{ +sp<ISensorEventConnection> SensorService::createSensorEventConnection(const String8& packageName, + int requestedMode, const String16& opPackageName) { + // Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION. + if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) { + return NULL; + } + + Mutex::Autolock _l(mLock); + // To create a client in DATA_INJECTION mode to inject data, SensorService should already be + // operating in DI mode. + if (requestedMode == DATA_INJECTION) { + if (mCurrentOperatingMode != DATA_INJECTION) return NULL; + if (!isWhiteListedPackage(packageName)) return NULL; + } + uid_t uid = IPCThreadState::self()->getCallingUid(); - sp<SensorEventConnection> result(new SensorEventConnection(this, uid)); + sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName, + requestedMode == DATA_INJECTION, opPackageName)); + if (requestedMode == DATA_INJECTION) { + if (mActiveConnections.indexOf(result) < 0) { + mActiveConnections.add(result); + } + // Add the associated file descriptor to the Looper for polling whenever there is data to + // be injected. + result->updateLooperRegistration(mLooper); + } return result; } +int SensorService::isDataInjectionEnabled() { + Mutex::Autolock _l(mLock); + return (mCurrentOperatingMode == DATA_INJECTION); +} + +status_t SensorService::resetToNormalMode() { + Mutex::Autolock _l(mLock); + return resetToNormalModeLocked(); +} + +status_t SensorService::resetToNormalModeLocked() { + SensorDevice& dev(SensorDevice::getInstance()); + dev.enableAllSensors(); + status_t err = dev.setMode(NORMAL); + mCurrentOperatingMode = NORMAL; + return err; +} + void SensorService::cleanupConnection(SensorEventConnection* c) { Mutex::Autolock _l(mLock); @@ -708,7 +828,8 @@ Sensor SensorService::getSensorFromHandle(int handle) const { } status_t SensorService::enable(const sp<SensorEventConnection>& connection, - int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags) + int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags, + const String16& opPackageName) { if (mInitCheck != NO_ERROR) return mInitCheck; @@ -718,11 +839,16 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, return BAD_VALUE; } - if (!verifyCanAccessSensor(sensor->getSensor(), "Tried enabling")) { + if (!canAccessSensor(sensor->getSensor(), "Tried enabling", opPackageName)) { return BAD_VALUE; } Mutex::Autolock _l(mLock); + if ((mCurrentOperatingMode == RESTRICTED || mCurrentOperatingMode == DATA_INJECTION) + && !isWhiteListedPackage(connection->getPackageName())) { + return INVALID_OPERATION; + } + SensorRecord* rec = mActiveSensors.valueFor(handle); if (rec == 0) { rec = new SensorRecord(connection); @@ -738,14 +864,24 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ON_CHANGE) { // NOTE: The wake_up flag of this event may get set to // WAKE_UP_SENSOR_EVENT_NEEDS_ACK if this is a wake_up event. - sensors_event_t& event(mLastEventSeen.editValueFor(handle)); - if (event.version == sizeof(sensors_event_t)) { - if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) { - setWakeLockAcquiredLocked(true); - } - connection->sendEvents(&event, 1, NULL); - if (!connection->needsWakeLock() && mWakeLockAcquired) { - checkWakeLockStateLocked(); + CircularBuffer *circular_buf = mLastEventSeen.valueFor(handle); + if (circular_buf) { + sensors_event_t event; + memset(&event, 0, sizeof(event)); + // It is unlikely that this buffer is empty as the sensor is already active. + // One possible corner case may be two applications activating an on-change + // sensor at the same time. + if(circular_buf->populateLastEvent(&event)) { + event.sensor = handle; + if (event.version == sizeof(sensors_event_t)) { + if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) { + setWakeLockAcquiredLocked(true); + } + connection->sendEvents(&event, 1, NULL); + if (!connection->needsWakeLock() && mWakeLockAcquired) { + checkWakeLockStateLocked(); + } + } } } } @@ -773,7 +909,7 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, "rate=%" PRId64 " timeout== %" PRId64"", handle, reservedFlags, samplingPeriodNs, maxBatchReportLatencyNs); - status_t err = sensor->batch(connection.get(), handle, reservedFlags, samplingPeriodNs, + status_t err = sensor->batch(connection.get(), handle, 0, samplingPeriodNs, maxBatchReportLatencyNs); // Call flush() before calling activate() on the sensor. Wait for a first flush complete @@ -798,6 +934,19 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, if (err == NO_ERROR) { connection->updateLooperRegistration(mLooper); + SensorRegistrationInfo ®_info = + mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex); + reg_info.mSensorHandle = handle; + reg_info.mSamplingRateUs = samplingPeriodNs/1000; + reg_info.mMaxReportLatencyUs = maxBatchReportLatencyNs/1000; + reg_info.mActivated = true; + reg_info.mPackageName = connection->getPackageName(); + time_t rawtime = time(NULL); + struct tm * timeinfo = localtime(&rawtime); + reg_info.mHour = timeinfo->tm_hour; + reg_info.mMin = timeinfo->tm_min; + reg_info.mSec = timeinfo->tm_sec; + mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE; } if (err != NO_ERROR) { @@ -818,6 +967,20 @@ status_t SensorService::disable(const sp<SensorEventConnection>& connection, if (err == NO_ERROR) { SensorInterface* sensor = mSensorMap.valueFor(handle); err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE); + + } + if (err == NO_ERROR) { + SensorRegistrationInfo ®_info = + mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex); + reg_info.mActivated = false; + reg_info.mPackageName= connection->getPackageName(); + reg_info.mSensorHandle = handle; + time_t rawtime = time(NULL); + struct tm * timeinfo = localtime(&rawtime); + reg_info.mHour = timeinfo->tm_hour; + reg_info.mMin = timeinfo->tm_min; + reg_info.mSec = timeinfo->tm_sec; + mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE; } return err; } @@ -852,7 +1015,7 @@ status_t SensorService::cleanupWithoutDisableLocked( } status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection, - int handle, nsecs_t ns) + int handle, nsecs_t ns, const String16& opPackageName) { if (mInitCheck != NO_ERROR) return mInitCheck; @@ -861,7 +1024,7 @@ status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection if (!sensor) return BAD_VALUE; - if (!verifyCanAccessSensor(sensor->getSensor(), "Tried configuring")) { + if (!canAccessSensor(sensor->getSensor(), "Tried configuring", opPackageName)) { return BAD_VALUE; } @@ -876,7 +1039,8 @@ status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection return sensor->setDelay(connection.get(), handle, ns); } -status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection) { +status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection, + const String16& opPackageName) { if (mInitCheck != NO_ERROR) return mInitCheck; SensorDevice& dev(SensorDevice::getInstance()); const int halVersion = dev.getHalDeviceVersion(); @@ -896,6 +1060,10 @@ status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection) // flush complete event. connection->incrementPendingFlushCount(handle); } else { + if (!canAccessSensor(sensor->getSensor(), "Tried flushing", opPackageName)) { + err = INVALID_OPERATION; + continue; + } status_t err_flush = sensor->flush(connection.get(), handle); if (err_flush == NO_ERROR) { SensorRecord* rec = mActiveSensors.valueFor(handle); @@ -907,23 +1075,42 @@ status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection) return err; } -bool SensorService::canAccessSensor(const Sensor& sensor) { - return (sensor.getRequiredPermission().isEmpty()) || - PermissionCache::checkCallingPermission(String16(sensor.getRequiredPermission())); -} +bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation, + const String16& opPackageName) { + const String8& requiredPermission = sensor.getRequiredPermission(); -bool SensorService::verifyCanAccessSensor(const Sensor& sensor, const char* operation) { - if (canAccessSensor(sensor)) { + if (requiredPermission.length() <= 0) { return true; + } + + bool hasPermission = false; + + // Runtime permissions can't use the cache as they may change. + if (sensor.isRequiredPermissionRuntime()) { + hasPermission = checkPermission(String16(requiredPermission), + IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); } else { - String8 errorMessage; - errorMessage.appendFormat( - "%s a sensor (%s) without holding its required permission: %s", - operation, - sensor.getName().string(), - sensor.getRequiredPermission().string()); + hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission)); + } + + if (!hasPermission) { + ALOGE("%s a sensor (%s) without holding its required permission: %s", + operation, sensor.getName().string(), sensor.getRequiredPermission().string()); return false; } + + const int32_t opCode = sensor.getRequiredAppOp(); + if (opCode >= 0) { + AppOpsManager appOps; + if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName) + != AppOpsManager::MODE_ALLOWED) { + ALOGE("%s a sensor (%s) without enabled required app op: %D", + operation, sensor.getName().string(), opCode); + return false; + } + } + + return true; } void SensorService::checkWakeLockState() { @@ -969,6 +1156,33 @@ void SensorService::populateActiveConnections( } } +bool SensorService::isWhiteListedPackage(const String8& packageName) { + return (packageName.contains(mWhiteListedPackage.string())); +} + +int SensorService::getNumEventsForSensorType(int sensor_event_type) { + switch (sensor_event_type) { + case SENSOR_TYPE_ROTATION_VECTOR: + case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR: + return 5; + + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + return 6; + + case SENSOR_TYPE_GAME_ROTATION_VECTOR: + return 4; + + case SENSOR_TYPE_SIGNIFICANT_MOTION: + case SENSOR_TYPE_STEP_DETECTOR: + case SENSOR_TYPE_STEP_COUNTER: + return 1; + + default: + return 3; + } +} + // --------------------------------------------------------------------------- SensorService::SensorRecord::SensorRecord( const sp<SensorEventConnection>& connection) @@ -1025,12 +1239,121 @@ SensorService::SensorRecord::getFirstPendingFlushConnection() { return NULL; } +void SensorService::SensorRecord::clearAllPendingFlushConnections() { + mPendingFlushConnections.clear(); +} + + +// --------------------------------------------------------------------------- +SensorService::TrimmedSensorEvent::TrimmedSensorEvent(int sensorType) { + mTimestamp = -1; + const int numData = SensorService::getNumEventsForSensorType(sensorType); + if (sensorType == SENSOR_TYPE_STEP_COUNTER) { + mStepCounter = 0; + } else { + mData = new float[numData]; + for (int i = 0; i < numData; ++i) { + mData[i] = -1.0; + } + } + mHour = mMin = mSec = INT32_MIN; +} + +bool SensorService::TrimmedSensorEvent::isSentinel(const TrimmedSensorEvent& event) { + return (event.mHour == INT32_MIN && event.mMin == INT32_MIN && event.mSec == INT32_MIN); +} +// -------------------------------------------------------------------------- +SensorService::CircularBuffer::CircularBuffer(int sensor_event_type) { + mNextInd = 0; + mBufSize = CIRCULAR_BUF_SIZE; + if (sensor_event_type == SENSOR_TYPE_STEP_COUNTER || + sensor_event_type == SENSOR_TYPE_SIGNIFICANT_MOTION || + sensor_event_type == SENSOR_TYPE_ACCELEROMETER) { + mBufSize = CIRCULAR_BUF_SIZE * 5; + } + mTrimmedSensorEventArr = new TrimmedSensorEvent *[mBufSize]; + mSensorType = sensor_event_type; + for (int i = 0; i < mBufSize; ++i) { + mTrimmedSensorEventArr[i] = new TrimmedSensorEvent(mSensorType); + } +} + +void SensorService::CircularBuffer::addEvent(const sensors_event_t& sensor_event) { + TrimmedSensorEvent *curr_event = mTrimmedSensorEventArr[mNextInd]; + curr_event->mTimestamp = sensor_event.timestamp; + if (mSensorType == SENSOR_TYPE_STEP_COUNTER) { + curr_event->mStepCounter = sensor_event.u64.step_counter; + } else { + memcpy(curr_event->mData, sensor_event.data, + sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType)); + } + time_t rawtime = time(NULL); + struct tm * timeinfo = localtime(&rawtime); + curr_event->mHour = timeinfo->tm_hour; + curr_event->mMin = timeinfo->tm_min; + curr_event->mSec = timeinfo->tm_sec; + mNextInd = (mNextInd + 1) % mBufSize; +} + +void SensorService::CircularBuffer::printBuffer(String8& result) const { + const int numData = SensorService::getNumEventsForSensorType(mSensorType); + int i = mNextInd, eventNum = 1; + result.appendFormat("last %d events = < ", mBufSize); + do { + if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[i])) { + // Sentinel, ignore. + i = (i + 1) % mBufSize; + continue; + } + result.appendFormat("%d) ", eventNum++); + if (mSensorType == SENSOR_TYPE_STEP_COUNTER) { + result.appendFormat("%llu,", mTrimmedSensorEventArr[i]->mStepCounter); + } else { + for (int j = 0; j < numData; ++j) { + result.appendFormat("%5.1f,", mTrimmedSensorEventArr[i]->mData[j]); + } + } + result.appendFormat("%lld %02d:%02d:%02d ", mTrimmedSensorEventArr[i]->mTimestamp, + mTrimmedSensorEventArr[i]->mHour, mTrimmedSensorEventArr[i]->mMin, + mTrimmedSensorEventArr[i]->mSec); + i = (i + 1) % mBufSize; + } while (i != mNextInd); + result.appendFormat(">\n"); +} + +bool SensorService::CircularBuffer::populateLastEvent(sensors_event_t *event) { + int lastEventInd = (mNextInd - 1 + mBufSize) % mBufSize; + // Check if the buffer is empty. + if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[lastEventInd])) { + return false; + } + event->version = sizeof(sensors_event_t); + event->type = mSensorType; + event->timestamp = mTrimmedSensorEventArr[lastEventInd]->mTimestamp; + if (mSensorType == SENSOR_TYPE_STEP_COUNTER) { + event->u64.step_counter = mTrimmedSensorEventArr[lastEventInd]->mStepCounter; + } else { + memcpy(event->data, mTrimmedSensorEventArr[lastEventInd]->mData, + sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType)); + } + return true; +} + +SensorService::CircularBuffer::~CircularBuffer() { + for (int i = 0; i < mBufSize; ++i) { + delete mTrimmedSensorEventArr[i]; + } + delete [] mTrimmedSensorEventArr; +} + // --------------------------------------------------------------------------- SensorService::SensorEventConnection::SensorEventConnection( - const sp<SensorService>& service, uid_t uid) + const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode, + const String16& opPackageName) : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false), - mDead(false), mEventCache(NULL), mCacheSize(0), mMaxCacheSize(0) { + mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL), + mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) { mChannel = new BitTube(mService->mSocketBufferSize); #if DEBUG_CONNECTIONS mEventsReceived = mEventsSentFromCache = mEventsSent = 0; @@ -1062,8 +1385,10 @@ void SensorService::SensorEventConnection::resetWakeLockRefCount() { void SensorService::SensorEventConnection::dump(String8& result) { Mutex::Autolock _l(mConnectionLock); - result.appendFormat("\t WakeLockRefCount %d | uid %d | cache size %d | max cache size %d\n", - mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize); + result.appendFormat("\tOperating Mode: %s\n",mDataInjectionMode ? "DATA_INJECTION" : "NORMAL"); + result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | " + "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize, + mMaxCacheSize); for (size_t i = 0; i < mSensorInfo.size(); ++i) { const FlushInfo& flushInfo = mSensorInfo.valueAt(i); result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n", @@ -1087,7 +1412,8 @@ void SensorService::SensorEventConnection::dump(String8& result) { bool SensorService::SensorEventConnection::addSensor(int32_t handle) { Mutex::Autolock _l(mConnectionLock); - if (!verifyCanAccessSensor(mService->getSensorFromHandle(handle), "Tried adding")) { + if (!canAccessSensor(mService->getSensorFromHandle(handle), + "Tried adding", mOpPackageName)) { return false; } if (mSensorInfo.indexOfKey(handle) < 0) { @@ -1126,6 +1452,10 @@ bool SensorService::SensorEventConnection::hasOneShotSensors() const { return false; } +String8 SensorService::SensorEventConnection::getPackageName() const { + return mPackageName; +} + void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle, bool value) { Mutex::Autolock _l(mConnectionLock); @@ -1143,7 +1473,8 @@ void SensorService::SensorEventConnection::updateLooperRegistration(const sp<Loo void SensorService::SensorEventConnection::updateLooperRegistrationLocked( const sp<Looper>& looper) { - bool isConnectionActive = mSensorInfo.size() > 0; + bool isConnectionActive = (mSensorInfo.size() > 0 && !mDataInjectionMode) || + mDataInjectionMode; // If all sensors are unregistered OR Looper has encountered an error, we // can remove the Fd from the Looper if it has been previously added. if (!isConnectionActive || mDead) { @@ -1157,6 +1488,7 @@ void SensorService::SensorEventConnection::updateLooperRegistrationLocked( int looper_flags = 0; if (mCacheSize > 0) looper_flags |= ALOOPER_EVENT_OUTPUT; + if (mDataInjectionMode) looper_flags |= ALOOPER_EVENT_INPUT; for (size_t i = 0; i < mSensorInfo.size(); ++i) { const int handle = mSensorInfo.keyAt(i); if (mService->getSensorFromHandle(handle).isWakeUpSensor()) { @@ -1200,7 +1532,7 @@ status_t SensorService::SensorEventConnection::sendEvents( sensors_event_t* scratch, SensorEventConnection const * const * mapFlushEventsToConnections) { // filter out events not for this connection - size_t count = 0; + int count = 0; Mutex::Autolock _l(mConnectionLock); if (scratch) { size_t i=0; @@ -1492,7 +1824,7 @@ status_t SensorService::SensorEventConnection::enableDisable( status_t err; if (enabled) { err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs, - reservedFlags); + reservedFlags, mOpPackageName); } else { err = mService->disable(this, handle); @@ -1503,11 +1835,11 @@ status_t SensorService::SensorEventConnection::enableDisable( status_t SensorService::SensorEventConnection::setEventRate( int handle, nsecs_t samplingPeriodNs) { - return mService->setEventRate(this, handle, samplingPeriodNs); + return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName); } status_t SensorService::SensorEventConnection::flush() { - return mService->flushSensor(this); + return mService->flushSensor(this, mOpPackageName); } int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* /*data*/) { @@ -1523,26 +1855,55 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* updateLooperRegistrationLocked(mService->getLooper()); } mService->checkWakeLockState(); + if (mDataInjectionMode) { + // If the Looper has encountered some error in data injection mode, reset SensorService + // back to normal mode. + mService->resetToNormalMode(); + mDataInjectionMode = false; + } return 1; } if (events & ALOOPER_EVENT_INPUT) { - uint32_t numAcks = 0; - ssize_t ret = ::recv(fd, &numAcks, sizeof(numAcks), MSG_DONTWAIT); + unsigned char buf[sizeof(sensors_event_t)]; + ssize_t numBytesRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT); { Mutex::Autolock _l(mConnectionLock); - // Sanity check to ensure there are no read errors in recv, numAcks is always - // within the range and not zero. If any of the above don't hold reset mWakeLockRefCount - // to zero. - if (ret != sizeof(numAcks) || numAcks > mWakeLockRefCount || numAcks == 0) { - ALOGE("Looper read error ret=%d numAcks=%d", ret, numAcks); - mWakeLockRefCount = 0; - } else { - mWakeLockRefCount -= numAcks; - } + if (numBytesRead == sizeof(sensors_event_t)) { + if (!mDataInjectionMode) { + ALOGE("Data injected in normal mode, dropping event" + "package=%s uid=%d", mPackageName.string(), mUid); + // Unregister call backs. + return 0; + } + SensorDevice& dev(SensorDevice::getInstance()); + sensors_event_t sensor_event; + memset(&sensor_event, 0, sizeof(sensor_event)); + memcpy(&sensor_event, buf, sizeof(sensors_event_t)); + Sensor sensor = mService->getSensorFromHandle(sensor_event.sensor); + sensor_event.type = sensor.getType(); + dev.injectSensorData(&sensor_event); #if DEBUG_CONNECTIONS - mTotalAcksReceived += numAcks; + ++mEventsReceived; #endif + } else if (numBytesRead == sizeof(uint32_t)) { + uint32_t numAcks = 0; + memcpy(&numAcks, buf, numBytesRead); + // Sanity check to ensure there are no read errors in recv, numAcks is always + // within the range and not zero. If any of the above don't hold reset + // mWakeLockRefCount to zero. + if (numAcks > 0 && numAcks < mWakeLockRefCount) { + mWakeLockRefCount -= numAcks; + } else { + mWakeLockRefCount = 0; + } +#if DEBUG_CONNECTIONS + mTotalAcksReceived += numAcks; +#endif + } else { + // Read error, reset wakelock refcount. + mWakeLockRefCount = 0; + } } // Check if wakelock can be released by sensorservice. mConnectionLock needs to be released // here as checkWakeLockState() will need it. @@ -1561,8 +1922,8 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* } int SensorService::SensorEventConnection::computeMaxCacheSizeLocked() const { - int fifoWakeUpSensors = 0; - int fifoNonWakeUpSensors = 0; + size_t fifoWakeUpSensors = 0; + size_t fifoNonWakeUpSensors = 0; for (size_t i = 0; i < mSensorInfo.size(); ++i) { const Sensor& sensor = mService->getSensorFromHandle(mSensorInfo.keyAt(i)); if (sensor.getFifoReservedEventCount() == sensor.getFifoMaxEventCount()) { diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index e9ca3a5..9a573ae 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -27,6 +27,7 @@ #include <utils/AndroidThreads.h> #include <utils/RefBase.h> #include <utils/Looper.h> +#include <utils/String8.h> #include <binder/BinderService.h> @@ -52,6 +53,9 @@ // For older HALs which don't support batching, use a smaller socket buffer size. #define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024 +#define CIRCULAR_BUF_SIZE 10 +#define SENSOR_REGISTRATIONS_BUF_SIZE 20 + struct sensors_poll_device_t; struct sensors_module_t; @@ -65,6 +69,51 @@ class SensorService : { friend class BinderService<SensorService>; + enum Mode { + // The regular operating mode where any application can register/unregister/call flush on + // sensors. + NORMAL = 0, + // This mode is only used for testing purposes. Not all HALs support this mode. In this + // mode, the HAL ignores the sensor data provided by physical sensors and accepts the data + // that is injected from the SensorService as if it were the real sensor data. This mode + // is primarily used for testing various algorithms like vendor provided SensorFusion, + // Step Counter and Step Detector etc. Typically in this mode, there will be a client + // (a SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps + // can unregister and register for any sensor that supports injection. Registering to sensors + // that do not support injection will give an error. + // TODO(aakella) : Allow exactly one client to inject sensor data at a time. + DATA_INJECTION = 1, + // This mode is used only for testing sensors. Each sensor can be tested in isolation with + // the required sampling_rate and maxReportLatency parameters without having to think about + // the data rates requested by other applications. End user devices are always expected to be + // in NORMAL mode. When this mode is first activated, all active sensors from all connections + // are disabled. Calling flush() will return an error. In this mode, only the requests from + // selected apps whose package names are whitelisted are allowed (typically CTS apps). Only + // these apps can register/unregister/call flush() on sensors. If SensorService switches to + // NORMAL mode again, all sensors that were previously registered to are activated with the + // corresponding paramaters if the application hasn't unregistered for sensors in the mean + // time. + // NOTE: Non whitelisted app whose sensors were previously deactivated may still receive + // events if a whitelisted app requests data from the same sensor. + RESTRICTED = 2 + + // State Transitions supported. + // RESTRICTED <--- NORMAL ---> DATA_INJECTION + // ---> <--- + + // Shell commands to switch modes in SensorService. + // 1) Put SensorService in RESTRICTED mode with packageName .cts. If it is already in + // restricted mode it is treated as a NO_OP (and packageName is NOT changed). + // $ adb shell dumpsys sensorservice restrict .cts. + // + // 2) Put SensorService in DATA_INJECTION mode with packageName .xts. If it is already in + // data_injection mode it is treated as a NO_OP (and packageName is NOT changed). + // $ adb shell dumpsys sensorservice data_injection .xts. + // + // 3) Reset sensorservice back to NORMAL mode. + // $ adb shell dumpsys sensorservice enable + }; + static const char* WAKE_LOCK_NAME; static char const* getServiceName() ANDROID_API { return "sensorservice"; } @@ -77,8 +126,10 @@ class SensorService : virtual bool threadLoop(); // ISensorServer interface - virtual Vector<Sensor> getSensorList(); - virtual sp<ISensorEventConnection> createSensorEventConnection(); + virtual Vector<Sensor> getSensorList(const String16& opPackageName); + virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName, + int requestedMode, const String16& opPackageName); + virtual int isDataInjectionEnabled(); virtual status_t dump(int fd, const Vector<String16>& args); class SensorEventConnection : public BnSensorEventConnection, public LooperCallback { @@ -133,7 +184,6 @@ class SensorService : // connection FD may be added to the Looper. The flags to set are determined by the internal // state of the connection. FDs are added to the looper when wake-up sensors are registered // (to poll for acknowledgements) and when write fails on the socket when there are too many - // events (to poll when the FD is available for writing). FDs are removed when there is an // error and the other end hangs up or when this client unregisters for this connection. void updateLooperRegistration(const sp<Looper>& looper); void updateLooperRegistrationLocked(const sp<Looper>& looper); @@ -156,6 +206,8 @@ class SensorService : // mWakeLockRefCount is reset to zero. needsWakeLock method will always return false, if // this flag is set. bool mDead; + + bool mDataInjectionMode; struct FlushInfo { // The number of flush complete events dropped for this sensor is stored here. // They are sent separately before the next batch of events. @@ -169,14 +221,16 @@ class SensorService : KeyedVector<int, FlushInfo> mSensorInfo; sensors_event_t *mEventCache; int mCacheSize, mMaxCacheSize; - + String8 mPackageName; + const String16 mOpPackageName; #if DEBUG_CONNECTIONS int mEventsReceived, mEventsSent, mEventsSentFromCache; int mTotalAcksNeeded, mTotalAcksReceived; #endif public: - SensorEventConnection(const sp<SensorService>& service, uid_t uid); + SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName, + bool isDataInjectionMode, const String16& opPackageName); status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch, @@ -190,6 +244,7 @@ class SensorService : void dump(String8& result); bool needsWakeLock(); void resetWakeLockRefCount(); + String8 getPackageName() const; uid_t getUid() const { return mUid; } }; @@ -208,6 +263,7 @@ class SensorService : void addPendingFlushConnection(const sp<SensorEventConnection>& connection); void removeFirstPendingFlushConnection(); SensorEventConnection * getFirstPendingFlushConnection(); + void clearAllPendingFlushConnections(); }; class SensorEventAckReceiver : public Thread { @@ -217,6 +273,63 @@ class SensorService : SensorEventAckReceiver(const sp<SensorService>& service): mService(service) {} }; + // sensor_event_t with only the data and the timestamp. + struct TrimmedSensorEvent { + union { + float *mData; + uint64_t mStepCounter; + }; + // Timestamp from the sensor_event. + int64_t mTimestamp; + // HH:MM:SS local time at which this sensor event is read at SensorService. Useful + // for debugging. + int32_t mHour, mMin, mSec; + + TrimmedSensorEvent(int sensorType); + static bool isSentinel(const TrimmedSensorEvent& event); + + ~TrimmedSensorEvent() { + delete [] mData; + } + }; + + // A circular buffer of TrimmedSensorEvents. The size of this buffer is typically 10. The + // last N events generated from the sensor are stored in this buffer. The buffer is NOT + // cleared when the sensor unregisters and as a result one may see very old data in the + // dumpsys output but this is WAI. + class CircularBuffer { + int mNextInd; + int mSensorType; + int mBufSize; + TrimmedSensorEvent ** mTrimmedSensorEventArr; + public: + CircularBuffer(int sensor_event_type); + void addEvent(const sensors_event_t& sensor_event); + void printBuffer(String8& buffer) const; + bool populateLastEvent(sensors_event_t *event); + ~CircularBuffer(); + }; + + struct SensorRegistrationInfo { + int32_t mSensorHandle; + String8 mPackageName; + bool mActivated; + int32_t mSamplingRateUs; + int32_t mMaxReportLatencyUs; + int32_t mHour, mMin, mSec; + + SensorRegistrationInfo() : mPackageName() { + mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN; + mHour = mMin = mSec = INT32_MIN; + mActivated = false; + } + + static bool isSentinel(const SensorRegistrationInfo& info) { + return (info.mHour == INT32_MIN && info.mMin == INT32_MIN && info.mSec == INT32_MIN); + } + }; + + static int getNumEventsForSensorType(int sensor_event_type); String8 getSensorName(int handle) const; bool isVirtualSensor(int handle) const; Sensor getSensorFromHandle(int handle) const; @@ -231,8 +344,8 @@ class SensorService : const sp<SensorEventConnection>& connection, int handle); void cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection, sensors_event_t const* buffer, const int count); - static bool canAccessSensor(const Sensor& sensor); - static bool verifyCanAccessSensor(const Sensor& sensor, const char* operation); + static bool canAccessSensor(const Sensor& sensor, const char* operation, + const String16& opPackageName); // SensorService acquires a partial wakelock for delivering events from wake up sensors. This // method checks whether all the events from these wake up sensors have been delivered to the // corresponding applications, if yes the wakelock is released. @@ -261,6 +374,15 @@ class SensorService : // to the output vector. void populateActiveConnections(SortedVector< sp<SensorEventConnection> >* activeConnections); + // If SensorService is operating in RESTRICTED mode, only select whitelisted packages are + // allowed to register for or call flush on sensors. Typically only cts test packages are + // allowed. + bool isWhiteListedPackage(const String8& packageName); + + // Reset the state of SensorService to NORMAL mode. + status_t resetToNormalMode(); + status_t resetToNormalModeLocked(); + // constants Vector<Sensor> mSensorList; Vector<Sensor> mUserSensorListDebug; @@ -282,17 +404,28 @@ class SensorService : bool mWakeLockAcquired; sensors_event_t *mSensorEventBuffer, *mSensorEventScratch; SensorEventConnection const **mMapFlushEventsToConnections; + Mode mCurrentOperatingMode; + // This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only + // applications with this packageName are allowed to activate/deactivate or call flush on + // sensors. To run CTS this is can be set to ".cts." and only CTS tests will get access to + // sensors. + String8 mWhiteListedPackage; // The size of this vector is constant, only the items are mutable - KeyedVector<int32_t, sensors_event_t> mLastEventSeen; + KeyedVector<int32_t, CircularBuffer *> mLastEventSeen; + int mNextSensorRegIndex; + Vector<SensorRegistrationInfo> mLastNSensorRegistrations; public: void cleanupConnection(SensorEventConnection* connection); status_t enable(const sp<SensorEventConnection>& connection, int handle, - nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags); + nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags, + const String16& opPackageName); status_t disable(const sp<SensorEventConnection>& connection, int handle); - status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns); - status_t flushSensor(const sp<SensorEventConnection>& connection); + status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns, + const String16& opPackageName); + status_t flushSensor(const sp<SensorEventConnection>& connection, + const String16& opPackageName); }; // --------------------------------------------------------------------------- diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp index 1025fa8..cfdf6a3 100644 --- a/services/sensorservice/tests/sensorservicetest.cpp +++ b/services/sensorservice/tests/sensorservicetest.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <inttypes.h> #include <android/sensor.h> #include <gui/Sensor.h> #include <gui/SensorManager.h> @@ -25,7 +26,7 @@ using namespace android; static nsecs_t sStartTime = 0; -int receiver(int fd, int events, void* data) +int receiver(__unused int fd, __unused int events, void* data) { sp<SensorEventQueue> q((SensorEventQueue*)data); ssize_t n; @@ -44,7 +45,7 @@ int receiver(int fd, int events, void* data) oldTimeStamp = buffer[i].timestamp; if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) { - printf("%lld\t%8f\t%8f\t%8f\t%f\n", + printf("%" PRId64 "\t%8f\t%8f\t%8f\t%f\n", buffer[i].timestamp, buffer[i].data[0], buffer[i].data[1], buffer[i].data[2], 1.0/t); @@ -59,9 +60,9 @@ int receiver(int fd, int events, void* data) } -int main(int argc, char** argv) +int main() { - SensorManager& mgr(SensorManager::getInstance()); + SensorManager mgr(String16("Sensor Service Test")); Sensor const* const* list; ssize_t count = mgr.getSensorList(&list); diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index f7d32d0..49389e0 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -93,7 +93,7 @@ status_t Client::onTransact( const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); const int self_pid = getpid(); - if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) { + if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)) { // we're called from a different process, do the real check if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) { diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp index a000a84..659c2c8 100644 --- a/services/surfaceflinger/DdmConnection.cpp +++ b/services/surfaceflinger/DdmConnection.cpp @@ -66,7 +66,7 @@ void DdmConnection::start(const char* name) { jint (*registerNatives)(JNIEnv* env, jclass clazz); registerNatives = reinterpret_cast<decltype(registerNatives)>( dlsym(libandroid_runtime_dso, - "Java_com_android_internal_util_WithFramework_registerNatives")); + "Java_com_android_internal_util_WithFramework_registerNatives")); ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror()); if (!JNI_CreateJavaVM || !registerNatives) { diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h index 96efc34..67142b6 100644 --- a/services/surfaceflinger/DispSync.h +++ b/services/surfaceflinger/DispSync.h @@ -139,7 +139,7 @@ private: enum { MAX_RESYNC_SAMPLES = 32 }; enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 }; enum { NUM_PRESENT_SAMPLES = 8 }; - enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 12 }; + enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 }; // mPeriod is the computed period of the modeled vsync events in // nanoseconds. diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index c8b36ec..2dad005 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -305,13 +305,16 @@ void HWComposer::vsync(int disp, int64_t timestamp) { } void HWComposer::hotplug(int disp, int connected) { - if (disp == HWC_DISPLAY_PRIMARY || disp >= VIRTUAL_DISPLAY_ID_BASE) { + if (disp >= VIRTUAL_DISPLAY_ID_BASE) { ALOGE("hotplug event received for invalid display: disp=%d connected=%d", disp, connected); return; } queryDisplayProperties(disp); - mEventHandler.onHotplugReceived(disp, bool(connected)); + // Do not teardown or recreate the primary display + if (disp != HWC_DISPLAY_PRIMARY) { + mEventHandler.onHotplugReceived(disp, bool(connected)); + } } static float getDefaultDensity(uint32_t width, uint32_t height) { @@ -461,7 +464,7 @@ sp<Fence> HWComposer::getDisplayFence(int disp) const { } uint32_t HWComposer::getFormat(int disp) const { - if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) { + if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) { return HAL_PIXEL_FORMAT_RGBA_8888; } else { return mDisplayData[disp].format; @@ -632,6 +635,7 @@ status_t HWComposer::setFramebufferTarget(int32_t id, } status_t HWComposer::prepare() { + Mutex::Autolock _l(mDisplayLock); for (size_t i=0 ; i<mNumDisplays ; i++) { DisplayData& disp(mDisplayData[i]); if (disp.framebufferTarget) { @@ -1142,6 +1146,7 @@ static String8 getFormatStr(PixelFormat format) { } void HWComposer::dump(String8& result) const { + Mutex::Autolock _l(mDisplayLock); if (mHwc) { result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc)); result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 28d8c65..cc98b4c 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -354,6 +354,8 @@ private: // mLists[i>0] can be NULL. that display is to be ignored struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS]; DisplayData mDisplayData[MAX_HWC_DISPLAYS]; + // protect mDisplayData from races between prepare and dump + mutable Mutex mDisplayLock; size_t mNumDisplays; cb_context* mCBContext; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 11cbdc6..ba4c198 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -530,6 +530,15 @@ status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) { return INVALID_OPERATION; } +status_t VirtualDisplaySurface::setGenerationNumber(uint32_t /* generation */) { + ALOGE("setGenerationNumber not supported on VirtualDisplaySurface"); + return INVALID_OPERATION; +} + +String8 VirtualDisplaySurface::getConsumerName() const { + return String8("VirtualDisplaySurface"); +} + void VirtualDisplaySurface::updateQueueBufferOutput( const QueueBufferOutput& qbo) { uint32_t w, h, transformHint, numPendingBuffers; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 97af980..6298751 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -116,6 +116,8 @@ private: virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); virtual status_t allowAllocation(bool allow); + virtual status_t setGenerationNumber(uint32_t generationNumber); + virtual String8 getConsumerName() const override; // // Utility methods diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 2944c63..5ff79a9 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -76,11 +76,15 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mFiltering(false), mNeedsFiltering(false), mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2), - mSecure(false), mProtectedByApp(false), mHasSurface(false), mClientRef(client), - mPotentialCursor(false) + mPotentialCursor(false), + mQueueItemLock(), + mQueueItemCondition(), + mQueueItems(), + mLastFrameNumberReceived(0), + mUpdateTexImageFailed(false) { mCurrentCrop.makeInvalid(); mFlinger->getRenderEngine().genTextures(1, &mTextureName); @@ -91,6 +95,8 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, layerFlags |= layer_state_t::eLayerHidden; if (flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; + if (flags & ISurfaceComposerClient::eSecure) + layerFlags |= layer_state_t::eLayerSecure; if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false; @@ -163,20 +169,54 @@ void Layer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope Mutex::Autolock lock(mQueueItemLock); + + // Reset the frame number tracker when we receive the first buffer after + // a frame number reset + if (item.mFrameNumber == 1) { + mLastFrameNumberReceived = 0; + } + + // Ensure that callbacks are handled in order + while (item.mFrameNumber != mLastFrameNumberReceived + 1) { + status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, + ms2ns(500)); + if (result != NO_ERROR) { + ALOGE("[%s] Timed out waiting on callback", mName.string()); + } + } + mQueueItems.push_back(item); + android_atomic_inc(&mQueuedFrames); + + // Wake up any pending callbacks + mLastFrameNumberReceived = item.mFrameNumber; + mQueueItemCondition.broadcast(); } - android_atomic_inc(&mQueuedFrames); mFlinger->signalLayerUpdate(); } void Layer::onFrameReplaced(const BufferItem& item) { Mutex::Autolock lock(mQueueItemLock); + + // Ensure that callbacks are handled in order + while (item.mFrameNumber != mLastFrameNumberReceived + 1) { + status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, + ms2ns(500)); + if (result != NO_ERROR) { + ALOGE("[%s] Timed out waiting on callback", mName.string()); + } + } + if (mQueueItems.empty()) { ALOGE("Can't replace a frame on an empty queue"); return; } mQueueItems.editItemAt(0) = item; + + // Wake up any pending callbacks + mLastFrameNumberReceived = item.mFrameNumber; + mQueueItemCondition.broadcast(); } void Layer::onSidebandStreamChanged() { @@ -217,7 +257,6 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, mFormat = format; mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false; - mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false; mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false; mCurrentOpacity = getOpacityForFormat(format); @@ -512,16 +551,7 @@ void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, const Transform& tr = hw->getTransform(); Region visible = tr.transform(visibleRegion.intersect(hw->getViewport())); layer.setVisibleRegionScreen(visible); - - // Pass full-surface damage down untouched - if (surfaceDamageRegion.isRect() && - surfaceDamageRegion.getBounds() == Rect::INVALID_RECT) { - layer.setSurfaceDamage(surfaceDamageRegion); - } else { - Region surfaceDamage = - tr.transform(surfaceDamageRegion.intersect(hw->getViewport())); - layer.setSurfaceDamage(surfaceDamage); - } + layer.setSurfaceDamage(surfaceDamageRegion); if (mSidebandStream.get()) { layer.setSidebandStream(mSidebandStream); @@ -821,6 +851,12 @@ bool Layer::isOpaque(const Layer::State& s) const return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity; } +bool Layer::isSecure() const +{ + const Layer::State& s(mDrawingState); + return (s.flags & layer_state_t::eLayerSecure); +} + bool Layer::isProtected() const { const sp<GraphicBuffer>& activeBuffer(mActiveBuffer); @@ -1065,11 +1101,26 @@ void Layer::useEmptyDamage() { // ---------------------------------------------------------------------------- bool Layer::shouldPresentNow(const DispSync& dispSync) const { + if (mSidebandStreamChanged) { + return true; + } + Mutex::Autolock lock(mQueueItemLock); + if (mQueueItems.empty()) { + return false; + } + auto timestamp = mQueueItems[0].mTimestamp; nsecs_t expectedPresent = mSurfaceFlingerConsumer->computeExpectedPresent(dispSync); - return mQueueItems.empty() ? - false : mQueueItems[0].mTimestamp < expectedPresent; + + // Ignore timestamps more than a second in the future + bool isPlausible = timestamp < (expectedPresent + s2ns(1)); + ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible " + "relative to expectedPresent %" PRId64, mName.string(), timestamp, + expectedPresent); + + bool isDue = timestamp < expectedPresent; + return isDue || !isPlausible; } bool Layer::onPreComposition() { @@ -1120,6 +1171,10 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) { // mSidebandStreamChanged was true mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream(); + if (mSidebandStream != NULL) { + setTransactionFlags(eTransactionNeeded); + mFlinger->setTransactionFlags(eTraversalNeeded); + } recomputeVisibleRegions = true; const State& s(getDrawingState()); @@ -1252,21 +1307,62 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions, getProducerStickyTransform() != 0); + uint64_t maxFrameNumber = 0; + { + Mutex::Autolock lock(mQueueItemLock); + maxFrameNumber = mLastFrameNumberReceived; + } + status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r, - mFlinger->mPrimaryDispSync); + mFlinger->mPrimaryDispSync, maxFrameNumber); if (updateResult == BufferQueue::PRESENT_LATER) { // Producer doesn't want buffer to be displayed yet. Signal a // layer update so we check again at the next opportunity. mFlinger->signalLayerUpdate(); return outDirtyRegion; + } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) { + // If the buffer has been rejected, remove it from the shadow queue + // and return early + Mutex::Autolock lock(mQueueItemLock); + mQueueItems.removeAt(0); + android_atomic_dec(&mQueuedFrames); + return outDirtyRegion; + } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) { + // This can occur if something goes wrong when trying to create the + // EGLImage for this buffer. If this happens, the buffer has already + // been released, so we need to clean up the queue and bug out + // early. + { + Mutex::Autolock lock(mQueueItemLock); + mQueueItems.clear(); + android_atomic_and(0, &mQueuedFrames); + } + + // Once we have hit this state, the shadow queue may no longer + // correctly reflect the incoming BufferQueue's contents, so even if + // updateTexImage starts working, the only safe course of action is + // to continue to ignore updates. + mUpdateTexImageFailed = true; + + return outDirtyRegion; } - // Remove this buffer from our internal queue tracker { // Autolock scope + auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber(); + Mutex::Autolock lock(mQueueItemLock); + + // Remove any stale buffers that have been dropped during + // updateTexImage + while (mQueueItems[0].mFrameNumber != currentFrameNumber) { + mQueueItems.removeAt(0); + android_atomic_dec(&mQueuedFrames); + } + mQueueItems.removeAt(0); } + // Decrement the queued-frames count. Signal another event if we // have more frames pending. if (android_atomic_dec(&mQueuedFrames) > 1) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 46c17e5..c1e5e9f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -174,7 +174,7 @@ public: * isSecure - true if this surface is secure, that is if it prevents * screenshots or VNC servers. */ - virtual bool isSecure() const { return mSecure; } + virtual bool isSecure() const; /* * isProtected - true if the layer may contain protected content in the @@ -339,9 +339,9 @@ protected: private: // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener - virtual void onFrameAvailable(const BufferItem& item); - virtual void onFrameReplaced(const BufferItem& item); - virtual void onSidebandStreamChanged(); + virtual void onFrameAvailable(const BufferItem& item) override; + virtual void onFrameReplaced(const BufferItem& item) override; + virtual void onSidebandStreamChanged() override; void commitTransaction(); @@ -402,7 +402,6 @@ private: mutable Texture mTexture; // page-flip thread (currently main thread) - bool mSecure; // no screenshots bool mProtectedByApp; // application requires protected path to external sink // protected by mLock @@ -416,7 +415,10 @@ private: // Local copy of the queued contents of the incoming BufferQueue mutable Mutex mQueueItemLock; + Condition mQueueItemCondition; Vector<BufferItem> mQueueItems; + uint64_t mLastFrameNumberReceived; + bool mUpdateTexImageFailed; // This is only modified from the main thread }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index 9fb555b..fb7af97 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -114,6 +114,14 @@ status_t MonitoredProducer::allowAllocation(bool allow) { return mProducer->allowAllocation(allow); } +status_t MonitoredProducer::setGenerationNumber(uint32_t generationNumber) { + return mProducer->setGenerationNumber(generationNumber); +} + +String8 MonitoredProducer::getConsumerName() const { + return mProducer->getConsumerName(); +} + IBinder* MonitoredProducer::onAsBinder() { return IInterface::asBinder(mProducer).get(); } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index b2f8293..da95766 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -54,6 +54,8 @@ public: virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); virtual status_t allowAllocation(bool allow); + virtual status_t setGenerationNumber(uint32_t generationNumber); + virtual String8 getConsumerName() const override; virtual IBinder* onAsBinder(); private: diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp index 1adcd1f..0dab872 100644 --- a/services/surfaceflinger/RenderEngine/Description.cpp +++ b/services/surfaceflinger/RenderEngine/Description.cpp @@ -88,5 +88,9 @@ void Description::setColorMatrix(const mat4& mtx) { mColorMatrixEnabled = (mtx != identity); } +const mat4& Description::getColorMatrix() const { + return mColorMatrix; +} + } /* namespace android */ diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h index 43b835f..8a3447c 100644 --- a/services/surfaceflinger/RenderEngine/Description.h +++ b/services/surfaceflinger/RenderEngine/Description.h @@ -66,6 +66,7 @@ public: void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); void setProjectionMatrix(const mat4& mtx); void setColorMatrix(const mat4& mtx); + const mat4& getColorMatrix() const; private: bool mUniformsDirty; diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp index 2e6af49..1a9f59b 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp @@ -262,14 +262,6 @@ void GLES11RenderEngine::drawMesh(const Mesh& mesh) { } } -void GLES11RenderEngine::beginGroup(const mat4& /*colorTransform*/) { - // doesn't do anything in GLES 1.1 -} - -void GLES11RenderEngine::endGroup() { - // doesn't do anything in GLES 1.1 -} - void GLES11RenderEngine::dump(String8& result) { RenderEngine::dump(result); } diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h index 87eb3e4..08de646 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h @@ -62,9 +62,6 @@ protected: virtual void drawMesh(const Mesh& mesh); - virtual void beginGroup(const mat4& colorTransform); - virtual void endGroup(); - virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; }; diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index 8712c9a..1fabaf5 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -169,6 +169,12 @@ void GLES20RenderEngine::setupLayerBlackedOut() { mState.setTexture(texture); } +mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) { + mat4 oldTransform = mState.getColorMatrix(); + mState.setColorMatrix(colorTransform); + return oldTransform; +} + void GLES20RenderEngine::disableTexturing() { mState.disableTexture(); } @@ -237,78 +243,6 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { } } -void GLES20RenderEngine::beginGroup(const mat4& colorTransform) { - - GLuint tname, name; - // create the texture - glGenTextures(1, &tname); - glBindTexture(GL_TEXTURE_2D, tname); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mVpWidth, mVpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - - // create a Framebuffer Object to render into - glGenFramebuffers(1, &name); - glBindFramebuffer(GL_FRAMEBUFFER, name); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); - - Group group; - group.texture = tname; - group.fbo = name; - group.width = mVpWidth; - group.height = mVpHeight; - group.colorTransform = colorTransform; - - mGroupStack.push(group); -} - -void GLES20RenderEngine::endGroup() { - - const Group group(mGroupStack.top()); - mGroupStack.pop(); - - // activate the previous render target - GLuint fbo = 0; - if (!mGroupStack.isEmpty()) { - fbo = mGroupStack.top().fbo; - } - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - // set our state - Texture texture(Texture::TEXTURE_2D, group.texture); - texture.setDimensions(group.width, group.height); - glBindTexture(GL_TEXTURE_2D, group.texture); - - mState.setPlaneAlpha(1.0f); - mState.setPremultipliedAlpha(true); - mState.setOpaque(false); - mState.setTexture(texture); - mState.setColorMatrix(group.colorTransform); - glDisable(GL_BLEND); - - Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2); - Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - Mesh::VertexArray<vec2> texCoord(mesh.getTexCoordArray<vec2>()); - position[0] = vec2(0, 0); - position[1] = vec2(group.width, 0); - position[2] = vec2(group.width, group.height); - position[3] = vec2(0, group.height); - texCoord[0] = vec2(0, 0); - texCoord[1] = vec2(1, 0); - texCoord[2] = vec2(1, 1); - texCoord[3] = vec2(0, 1); - drawMesh(mesh); - - // reset color matrix - mState.setColorMatrix(mat4()); - - // free our fbo and texture - glDeleteFramebuffers(1, &group.fbo); - glDeleteTextures(1, &group.texture); -} - void GLES20RenderEngine::dump(String8& result) { RenderEngine::dump(result); } diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index 3d6243e..819356a 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -72,14 +72,12 @@ protected: virtual void setupLayerTexturing(const Texture& texture); virtual void setupLayerBlackedOut(); virtual void setupFillWithColor(float r, float g, float b, float a); + virtual mat4 setupColorTransform(const mat4& colorTransform); virtual void disableTexturing(); virtual void disableBlending(); virtual void drawMesh(const Mesh& mesh); - virtual void beginGroup(const mat4& colorTransform); - virtual void endGroup(); - virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; }; diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp index 3f50cb0..ffd9be2 100644 --- a/services/surfaceflinger/RenderEngine/Mesh.cpp +++ b/services/surfaceflinger/RenderEngine/Mesh.cpp @@ -16,14 +16,40 @@ #include "Mesh.h" +#include <utils/Log.h> + namespace android { Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize) : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize), mPrimitive(primitive) { - mVertices = new float[(vertexSize + texCoordSize) * vertexCount]; - mStride = mVertexSize + mTexCoordsSize; + if (vertexCount == 0) { + mVertices = new float[1]; + mVertices[0] = 0.0f; + mStride = 0; + return; + } + + size_t stride = vertexSize + texCoordSize; + size_t remainder = (stride * vertexCount) / vertexCount; + // Since all of the input parameters are unsigned, if stride is less than + // either vertexSize or texCoordSize, it must have overflowed. remainder + // will be equal to stride as long as stride * vertexCount doesn't overflow. + if ((stride < vertexSize) || (remainder != stride)) { + ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, + texCoordSize); + mVertices = new float[1]; + mVertices[0] = 0.0f; + mVertexCount = 0; + mVertexSize = 0; + mTexCoordsSize = 0; + mStride = 0; + return; + } + + mVertices = new float[stride * vertexCount]; + mStride = stride; } Mesh::~Mesh() { diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp index 0de5cca..ba11259 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -199,10 +199,8 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { // un-premultiply if needed before linearization fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;"; } - fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(2.2));"; fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);"; fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;"; - fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));"; if (!needs.isOpaque() && needs.isPremultiplied()) { // and re-premultiply if needed after gamma correction fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;"; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 8d7529c..31a961e 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -99,18 +99,16 @@ public: virtual void setupLayerBlackedOut() = 0; virtual void setupFillWithColor(float r, float g, float b, float a) = 0; + virtual mat4 setupColorTransform(const mat4& /* colorTransform */) { + return mat4(); + } + virtual void disableTexturing() = 0; virtual void disableBlending() = 0; // drawing virtual void drawMesh(const Mesh& mesh) = 0; - // grouping - // creates a color-transform group, everything drawn in the group will be - // transformed by the given color transform when endGroup() is called. - virtual void beginGroup(const mat4& colorTransform) = 0; - virtual void endGroup() = 0; - // queries virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index df4ac2e..de0f921 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -149,7 +149,11 @@ SurfaceFlinger::SurfaceFlinger() mPrimaryHWVsyncEnabled(false), mHWVsyncAvailable(false), mDaltonize(false), - mHasColorMatrix(false) + mHasColorMatrix(false), + mHasPoweredOff(false), + mFrameBuckets(), + mTotalTime(0), + mLastSwapTime(0) { ALOGI("SurfaceFlinger is starting"); @@ -546,7 +550,7 @@ bool SurfaceFlinger::authenticateSurfaceTexture( status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayInfo>* configs) { - if (configs == NULL) { + if ((configs == NULL) || (display.get() == NULL)) { return BAD_VALUE; } @@ -997,8 +1001,8 @@ void SurfaceFlinger::postComposition() } } + const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); if (kIgnorePresentFences) { - const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); if (hw->isDisplayOn()) { enableHardwareVsync(); } @@ -1017,6 +1021,26 @@ void SurfaceFlinger::postComposition() } mAnimFrameTracker.advanceFrame(); } + + if (hw->getPowerMode() == HWC_POWER_MODE_OFF) { + return; + } + + nsecs_t currentTime = systemTime(); + if (mHasPoweredOff) { + mHasPoweredOff = false; + } else { + nsecs_t period = mPrimaryDispSync.getPeriod(); + nsecs_t elapsedTime = currentTime - mLastSwapTime; + size_t numPeriods = static_cast<size_t>(elapsedTime / period); + if (numPeriods < NUM_BUCKETS - 1) { + mFrameBuckets[numPeriods] += elapsedTime; + } else { + mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime; + } + mTotalTime += elapsedTime; + } + mLastSwapTime = currentTime; } void SurfaceFlinger::rebuildLayerStacks() { @@ -1848,9 +1872,9 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, if (mDaltonize) { colorMatrix = colorMatrix * mDaltonizer(); } - engine.beginGroup(colorMatrix); + mat4 oldMatrix = engine.setupColorTransform(colorMatrix); doComposeSurfaces(hw, dirtyRegion); - engine.endGroup(); + engine.setupColorTransform(oldMatrix); } // update the swap region and clear the dirty region @@ -1994,18 +2018,25 @@ void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Regio engine.fillRegionWithColor(region, height, 0, 0, 0, 0); } -void SurfaceFlinger::addClientLayer(const sp<Client>& client, +status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc) { + // add this layer to the current state list + { + Mutex::Autolock _l(mStateLock); + if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) { + return NO_MEMORY; + } + mCurrentState.layersSortedByZ.add(lbc); + mGraphicBufferProducerList.add(IInterface::asBinder(gbc)); + } + // attach this layer to the client client->attachLayer(handle, lbc); - // add this layer to the current state list - Mutex::Autolock _l(mStateLock); - mCurrentState.layersSortedByZ.add(lbc); - mGraphicBufferProducerList.add(IInterface::asBinder(gbc)); + return NO_ERROR; } status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) { @@ -2204,9 +2235,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setTransparentRegionHint(s.transparentRegion)) flags |= eTraversalNeeded; } - if ((what & layer_state_t::eVisibilityChanged) || - (what & layer_state_t::eOpacityChanged)) { - // TODO: should we just use an eFlagsChanged for this? + if (what & layer_state_t::eFlagsChanged) { if (layer->setFlags(s.flags, s.mask)) flags |= eTraversalNeeded; } @@ -2262,10 +2291,16 @@ status_t SurfaceFlinger::createLayer( break; } - if (result == NO_ERROR) { - addClientLayer(client, *handle, *gbp, layer); - setTransactionFlags(eTransactionNeeded); + if (result != NO_ERROR) { + return result; + } + + result = addClientLayer(client, *handle, *gbp, layer); + if (result != NO_ERROR) { + return result; } + + setTransactionFlags(eTransactionNeeded); return result; } @@ -2398,6 +2433,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, } mVisibleRegionsDirty = true; + mHasPoweredOff = true; repaintEverything(); } else if (mode == HWC_POWER_MODE_OFF) { if (type == DisplayDevice::DISPLAY_PRIMARY) { @@ -2498,6 +2534,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) mPrimaryDispSync.dump(result); dumpAll = false; } + + if ((index < numArgs) && + (args[index] == String16("--static-screen"))) { + index++; + dumpStaticScreenStats(result); + dumpAll = false; + } } if (dumpAll) { @@ -2601,6 +2644,23 @@ void SurfaceFlinger::logFrameStats() { result.append(config); } +void SurfaceFlinger::dumpStaticScreenStats(String8& result) const +{ + result.appendFormat("Static screen stats:\n"); + for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) { + float bucketTimeSec = mFrameBuckets[b] / 1e9; + float percent = 100.0f * + static_cast<float>(mFrameBuckets[b]) / mTotalTime; + result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n", + b + 1, bucketTimeSec, percent); + } + float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9; + float percent = 100.0f * + static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime; + result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n", + NUM_BUCKETS - 1, bucketTimeSec, percent); +} + void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, String8& result) const { @@ -2647,6 +2707,11 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY)); result.append("\n"); + // Dump static screen stats + result.append("\n"); + dumpStaticScreenStats(result); + result.append("\n"); + /* * Dump the visible layer list */ @@ -2794,7 +2859,7 @@ status_t SurfaceFlinger::onTransact( IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && + if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { ALOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); @@ -3253,8 +3318,12 @@ status_t SurfaceFlinger::captureScreenImplLocked( ATRACE_CALL(); // get screen geometry - const uint32_t hw_w = hw->getWidth(); - const uint32_t hw_h = hw->getHeight(); + uint32_t hw_w = hw->getWidth(); + uint32_t hw_h = hw->getHeight(); + + if (rotation & Transform::ROT_90) { + std::swap(hw_w, hw_h); + } if ((reqWidth > hw_w) || (reqHeight > hw_h)) { ALOGE("size mismatch (%d, %d) > (%d, %d)", @@ -3270,8 +3339,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( sp<Surface> sur = new Surface(producer, false); ANativeWindow* window = sur.get(); - status_t result = NO_ERROR; - if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) == NO_ERROR) { + status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); + if (result == NO_ERROR) { uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; @@ -3361,7 +3430,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( result = BAD_VALUE; } // queueBuffer takes ownership of syncFd - window->queueBuffer(window, buffer, syncFd); + result = window->queueBuffer(window, buffer, syncFd); } } else { result = BAD_VALUE; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a06d1be..3759a92 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -144,6 +144,8 @@ private: // every half hour. enum { LOG_FRAME_STATS_PERIOD = 30*60*60 }; + static const size_t MAX_LAYERS = 4096; + // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); @@ -305,7 +307,7 @@ private: status_t removeLayer(const sp<Layer>& layer); // add a layer to SurfaceFlinger - void addClientLayer(const sp<Client>& client, + status_t addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc); @@ -416,6 +418,8 @@ private: void logFrameStats(); + void dumpStaticScreenStats(String8& result) const; + /* ------------------------------------------------------------------------ * Attributes */ @@ -494,6 +498,13 @@ private: mat4 mColorMatrix; bool mHasColorMatrix; + + // Static screen stats + bool mHasPoweredOff; + static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ + nsecs_t mFrameBuckets[NUM_BUCKETS]; + nsecs_t mTotalTime; + nsecs_t mLastSwapTime; }; }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 19c497a..ed1f31b 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -32,7 +32,7 @@ namespace android { // --------------------------------------------------------------------------- status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, - const DispSync& dispSync) + const DispSync& dispSync, uint64_t maxFrameNumber) { ATRACE_CALL(); ALOGV("updateTexImage"); @@ -54,7 +54,8 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, // Acquire the next buffer. // In asynchronous mode the list is guaranteed to be one buffer // deep, while in synchronous mode we use the oldest buffer. - err = acquireBufferLocked(&item, computeExpectedPresent(dispSync)); + err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), + maxFrameNumber); if (err != NO_ERROR) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { err = NO_ERROR; @@ -74,7 +75,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, int buf = item.mBuf; if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) { releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR); - return NO_ERROR; + return BUFFER_REJECTED; } // Release the previous buffer. @@ -104,8 +105,9 @@ status_t SurfaceFlingerConsumer::bindTextureImage() } status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item, - nsecs_t presentWhen) { - status_t result = GLConsumer::acquireBufferLocked(item, presentWhen); + nsecs_t presentWhen, uint64_t maxFrameNumber) { + status_t result = GLConsumer::acquireBufferLocked(item, presentWhen, + maxFrameNumber); if (result == NO_ERROR) { mTransformToDisplayInverse = item->mTransformToDisplayInverse; mSurfaceDamage = item->mSurfaceDamage; diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h index 1aaba18..779e5b7 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -28,6 +28,8 @@ namespace android { */ class SurfaceFlingerConsumer : public GLConsumer { public: + static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8; + struct ContentsChangedListener: public FrameAvailableListener { virtual void onSidebandStreamChanged() = 0; }; @@ -47,13 +49,15 @@ public: virtual ~BufferRejecter() { } }; - virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen); + virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) override; // This version of updateTexImage() takes a functor that may be used to // reject the newly acquired buffer. Unlike the GLConsumer version, // this does not guarantee that the buffer has been bound to the GL // texture. - status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync); + status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, + uint64_t maxFrameNumber = 0); // See GLConsumer::bindTextureImageLocked(). status_t bindTextureImage(); diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 4d363c8..dcde512 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -16,6 +16,8 @@ #include <gtest/gtest.h> +#include <android/native_window.h> + #include <binder/IMemory.h> #include <gui/ISurfaceComposer.h> @@ -53,21 +55,23 @@ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, class ScreenCapture : public RefBase { public: static void captureScreen(sp<ScreenCapture>* sc) { - sp<IMemoryHeap> heap; - uint32_t w=0, h=0; - PixelFormat fmt=0; + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + IGraphicBufferProducer::QueueBufferOutput bufferOutput; + sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 0, 0, - 0, INT_MAX)); - ASSERT_TRUE(heap != NULL); - ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt); - *sc = new ScreenCapture(w, h, heap); + sp<IBinder> display(sf->getBuiltInDisplay( + ISurfaceComposer::eDisplayIdMain)); + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0, + 0, INT_MAX, false)); + *sc = new ScreenCapture(cpuConsumer); } void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { - const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base()); - const uint8_t* pixel = img + (4 * (y*mWidth + x)); + ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuf.format); + const uint8_t* img = static_cast<const uint8_t*>(mBuf.data); + const uint8_t* pixel = img + (4 * (y * mBuf.stride + x)); if (r != pixel[0] || g != pixel[1] || b != pixel[2]) { String8 err(String8::format("pixel @ (%3d, %3d): " "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", @@ -77,15 +81,17 @@ public: } private: - ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) : - mWidth(w), - mHeight(h), - mHeap(heap) - {} - - const uint32_t mWidth; - const uint32_t mHeight; - sp<IMemoryHeap> mHeap; + ScreenCapture(const sp<CpuConsumer>& cc) : + mCC(cc) { + EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuf)); + } + + ~ScreenCapture() { + mCC->unlockBuffer(mBuf); + } + + sp<CpuConsumer> mCC; + CpuConsumer::LockedBuffer mBuf; }; class LayerUpdateTest : public ::testing::Test { |