Merge "Consistent creation/destruction of user data." into nyc-dev
diff --git a/cmds/bugreportz/bugreportz.cpp b/cmds/bugreportz/bugreportz.cpp
index b6856bb..19d2d64 100644
--- a/cmds/bugreportz/bugreportz.cpp
+++ b/cmds/bugreportz/bugreportz.cpp
@@ -15,6 +15,7 @@
*/
#include <errno.h>
+#include <getopt.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -23,9 +24,47 @@
#include <cutils/properties.h>
#include <cutils/sockets.h>
-// TODO: code below was copy-and-pasted from bugreport.cpp (except by the timeout value);
-// should be reused instead.
-int main() {
+static constexpr char VERSION[] = "1.0";
+
+static void show_usage() {
+ fprintf(stderr,
+ "usage: bugreportz [-h | -v]\n"
+ " -h: to display this help message\n"
+ " -v: to display the version\n"
+ " or no arguments to generate a zipped bugreport\n");
+}
+
+static void show_version() {
+ fprintf(stderr, "%s\n", VERSION);
+}
+
+int main(int argc, char *argv[]) {
+
+ if (argc > 1) {
+ /* parse arguments */
+ int c;
+ while ((c = getopt(argc, argv, "vh")) != -1) {
+ switch (c) {
+ case 'h':
+ show_usage();
+ return EXIT_SUCCESS;
+ case 'v':
+ show_version();
+ return EXIT_SUCCESS;
+ default:
+ show_usage();
+ return EXIT_FAILURE;
+ }
+ }
+ // passed an argument not starting with -
+ if (optind > 1 || argv[optind] != nullptr) {
+ show_usage();
+ return EXIT_FAILURE;
+ }
+ }
+
+ // TODO: code below was copy-and-pasted from bugreport.cpp (except by the timeout value);
+ // should be reused instead.
// Start the dumpstatez service.
property_set("ctl.start", "dumpstatez");
@@ -42,7 +81,7 @@
if (s == -1) {
printf("Failed to connect to dumpstatez service: %s\n", strerror(errno));
- return 1;
+ return EXIT_FAILURE;
}
// Set a timeout so that if nothing is read in 10 minutes, we'll stop
@@ -81,13 +120,12 @@
printf(
"Failed to write data to stdout: read %zd, trying to send %zd (%s)\n",
bytes_read, bytes_to_send, strerror(errno));
- return 1;
+ return EXIT_FAILURE;
}
bytes_to_send -= bytes_written;
} while (bytes_written != 0 && bytes_to_send > 0);
}
close(s);
- return 0;
-
+ return EXIT_SUCCESS;
}
diff --git a/cmds/bugreportz/readme.md b/cmds/bugreportz/readme.md
new file mode 100644
index 0000000..85aafce
--- /dev/null
+++ b/cmds/bugreportz/readme.md
@@ -0,0 +1,12 @@
+# bugreportz protocol
+
+`bugreportz` is used to generate a zippped bugreport whose path is passed back to `adb`, using
+the simple protocol defined below.
+
+
+## Version 1.0
+On version 1.0, `bugreportz` does not generate any output on `stdout` until the bugreport is
+finished, when it then prints one line with the result:
+
+- `OK:<path_to_bugreport_file>` in case of success.
+- `FAIL:<error message>` in case of failure.
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index f9edc2a..64cf72e 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -91,6 +91,8 @@
size_t mExecutingThreadsCount;
// Maximum number for binder threads allowed for this process.
size_t mMaxThreads;
+ // Time when thread pool was emptied
+ int64_t mStarvationStartTimeMs;
mutable Mutex mLock; // protects everything below.
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 9161dbb..73f923c 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -138,6 +138,8 @@
status_t setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
status_t deferTransactionUntil(const sp<IBinder>& id,
const sp<IBinder>& handle, uint64_t frameNumber);
+ status_t setOverrideScalingMode(const sp<IBinder>& id,
+ int32_t overrideScalingMode);
status_t destroySurface(const sp<IBinder>& id);
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 35644db..bedebb6 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -77,6 +77,11 @@
// identified by handle reaches the given frameNumber
status_t deferTransactionUntil(sp<IBinder> handle, uint64_t frameNumber);
+ // Set an override scaling mode as documented in <system/window.h>
+ // the override scaling mode will take precedence over any client
+ // specified scaling mode. -1 will clear the override scaling mode.
+ status_t setOverrideScalingMode(int32_t overrideScalingMode);
+
static status_t writeSurfaceToParcel(
const sp<SurfaceControl>& control, Parcel* parcel);
diff --git a/include/input/Input.h b/include/input/Input.h
index 3b1c86b..55787e7 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -45,6 +45,19 @@
};
enum {
+
+ /**
+ * This flag indicates that the window that received this motion event is partly
+ * or wholly obscured by another visible window above it. This flag is set to true
+ * even if the event did not directly pass through the obscured area.
+ * A security sensitive application can check this flag to identify situations in which
+ * a malicious application may have covered up part of its content for the purpose
+ * of misleading the user or hijacking touches. An appropriate response might be
+ * to drop the suspect touches or to take additional precautions to confirm the user's
+ * actual intent.
+ */
+ AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2,
+
/* Motion event is inconsistent with previously sent motion events. */
AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
};
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 078720a..92d31d1 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -53,7 +53,8 @@
eLayerStackChanged = 0x00000080,
eCropChanged = 0x00000100,
eDeferTransaction = 0x00000200,
- eFinalCropChanged = 0x00000400
+ eFinalCropChanged = 0x00000400,
+ eOverrideScalingModeChanged = 0x00000800
};
layer_state_t()
@@ -61,7 +62,8 @@
x(0), y(0), z(0), w(0), h(0), layerStack(0),
alpha(0), flags(0), mask(0),
reserved(0), crop(Rect::INVALID_RECT),
- finalCrop(Rect::INVALID_RECT), frameNumber(0)
+ finalCrop(Rect::INVALID_RECT), frameNumber(0),
+ overrideScalingMode(-1)
{
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
@@ -93,6 +95,7 @@
Rect finalCrop;
sp<IBinder> handle;
uint64_t frameNumber;
+ int32_t overrideScalingMode;
// non POD must be last. see write/read
Region transparentRegion;
};
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 1cbcfe4..d90798f 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -24,12 +24,14 @@
#include <cutils/sched_policy.h>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
#include <utils/threads.h>
#include <private/binder/binder_module.h>
#include <private/binder/Static.h>
#include <errno.h>
+#include <inttypes.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
@@ -434,12 +436,25 @@
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;
+ if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
+ mProcess->mStarvationStartTimeMs == 0) {
+ mProcess->mStarvationStartTimeMs = uptimeMillis();
+ }
pthread_mutex_unlock(&mProcess->mThreadCountLock);
result = executeCommand(cmd);
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount--;
+ if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
+ mProcess->mStarvationStartTimeMs != 0) {
+ int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
+ if (starvationTimeMs > 100) {
+ ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
+ mProcess->mMaxThreads, starvationTimeMs);
+ }
+ mProcess->mStarvationStartTimeMs = 0;
+ }
pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
pthread_mutex_unlock(&mProcess->mThreadCountLock);
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index b221e51..f13f49f 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -343,6 +343,7 @@
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
+ , mStarvationStartTimeMs(0)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e43342e..d1c576e 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -41,6 +41,7 @@
output.write(finalCrop);
output.writeStrongBinder(handle);
output.writeUint64(frameNumber);
+ output.writeInt32(overrideScalingMode);
output.write(transparentRegion);
return NO_ERROR;
}
@@ -68,6 +69,7 @@
input.read(finalCrop);
handle = input.readStrongBinder();
frameNumber = input.readUint64();
+ overrideScalingMode = input.readInt32();
input.read(transparentRegion);
return NO_ERROR;
}
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 4b9a2ab..0340d6b 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -272,6 +272,11 @@
break;
}
+ // Set DYNAMIC_SENSOR_MASK and ADDITIONAL_INFO_MASK flag here. Compatible with HAL 1_3.
+ if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
+ mFlags |= (hwSensor->flags & (DYNAMIC_SENSOR_MASK | ADDITIONAL_INFO_MASK));
+ }
+
// Set DATA_INJECTION flag here. Defined in HAL 1_4.
if (halVersion >= SENSORS_DEVICE_API_VERSION_1_4) {
mFlags |= (hwSensor->flags & DATA_INJECTION_MASK);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 418892a..e33cc37 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -163,6 +163,8 @@
status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
const sp<IBinder>& id, const sp<IBinder>& handle,
uint64_t frameNumber);
+ status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client,
+ const sp<IBinder>& id, int32_t overrideScalingMode);
void setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
@@ -414,6 +416,33 @@
return NO_ERROR;
}
+status_t Composer::setOverrideScalingMode(
+ const sp<SurfaceComposerClient>& client,
+ const sp<IBinder>& id, int32_t overrideScalingMode) {
+ Mutex::Autolock lock(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s) {
+ return BAD_INDEX;
+ }
+
+ switch (overrideScalingMode) {
+ case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+ case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+ case -1:
+ break;
+ default:
+ ALOGE("unknown scaling mode: %d",
+ overrideScalingMode);
+ return BAD_VALUE;
+ }
+
+ s->what |= layer_state_t::eOverrideScalingModeChanged;
+ s->overrideScalingMode = overrideScalingMode;
+ return NO_ERROR;
+}
+
// ---------------------------------------------------------------------------
DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
@@ -650,6 +679,12 @@
return getComposer().deferTransactionUntil(this, id, handle, frameNumber);
}
+status_t SurfaceComposerClient::setOverrideScalingMode(
+ const sp<IBinder>& id, int32_t overrideScalingMode) {
+ return getComposer().setOverrideScalingMode(
+ this, id, overrideScalingMode);
+}
+
// ----------------------------------------------------------------------------
void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 184de71..314d83a 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -165,6 +165,12 @@
return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
}
+status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) {
+ status_t err = validate();
+ if (err < 0) return err;
+ return mClient->setOverrideScalingMode(mHandle, overrideScalingMode);
+}
+
status_t SurfaceControl::clearLayerFrameStats() const {
status_t err = validate();
if (err < 0) return err;
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 613b63b..df639cd 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -116,6 +116,7 @@
"EGL_EXT_buffer_age " // strongly recommended with partial_update
"EGL_KHR_create_context_no_error "
"EGL_KHR_mutable_render_buffer "
+ "EGL_EXT_yuv_surface "
;
// extensions not exposed to applications but used by the ANDROID system
diff --git a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
new file mode 100644
index 0000000..a6fae80
--- /dev/null
+++ b/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
@@ -0,0 +1,197 @@
+Name
+
+ ANDROID_create_native_client_buffer
+
+Name Strings
+
+ EGL_ANDROID_create_native_client_buffer
+
+Contributors
+
+ Craig Donner
+
+Contact
+
+ Craig Donner, Google Inc. (cdonner 'at' google.com)
+
+Status
+
+ Draft
+
+Version
+
+ Version 1, January 19, 2016
+
+Number
+
+ EGL Extension #XXX
+
+Dependencies
+
+ Requires EGL 1.2.
+
+ EGL_ANDROID_image_native_buffer and EGL_KHR_image_base are required.
+
+ This extension is written against the wording of the EGL 1.2
+ Specification as modified by EGL_KHR_image_base and
+ EGL_ANDROID_image_native_buffer.
+
+Overview
+
+ This extension allows creating an EGLClientBuffer backed by an Android
+ window buffer (struct ANativeWindowBuffer) which can be later used to
+ create an EGLImage.
+
+New Types
+
+ None.
+
+New Procedures and Functions
+
+EGLClientBuffer eglCreateNativeClientBufferANDROID(
+ const EGLint *attrib_list)
+
+New Tokens
+
+ EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143
+ EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001
+ EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002
+ EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004
+
+Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
+
+ Add the following to section 2.5.1 "EGLImage Specification" (as modified by
+ the EGL_KHR_image_base and EGL_ANDROID_image_native_buffer specifications),
+ below the description of eglCreateImageKHR:
+
+ "The command
+
+ EGLClientBuffer eglCreateNativeClientBufferANDROID(
+ const EGLint *attrib_list)
+
+ may be used to create an EGLClientBuffer backed by an ANativeWindowBuffer
+ struct. EGL implementations must guarantee that the lifetime of the
+ returned EGLClientBuffer is at least as long as the EGLImage(s) it is bound
+ to, following the lifetime semantics described below in section 2.5.2; the
+ EGLClientBuffer must be destroyed no earlier than when all of its associated
+ EGLImages are destroyed by eglDestroyImageKHR. <attrib_list> is a list of
+ attribute-value pairs which is used to specify the dimensions, format, and
+ usage of the underlying buffer structure. If <attrib_list> is non-NULL, the
+ last attribute specified in the list must be EGL_NONE.
+
+ Attribute names accepted in <attrib_list> are shown in Table aaa,
+ together with the <target> for which each attribute name is valid, and
+ the default value used for each attribute if it is not included in
+ <attrib_list>.
+
+ +---------------------------------+----------------------+---------------+
+ | Attribute | Description | Default Value |
+ | | | |
+ +---------------------------------+----------------------+---------------+
+ | EGL_NONE | Marks the end of the | N/A |
+ | | attribute-value list | |
+ | EGL_WIDTH | The width of the | 0 |
+ | | buffer data | |
+ | EGL_HEIGHT | The height of the | 0 |
+ | | buffer data | |
+ | EGL_RED_SIZE | The bits of Red in | 0 |
+ | | the color buffer | |
+ | EGL_GREEN_SIZE | The bits of Green in | 0 |
+ | | the color buffer | |
+ | EGL_BLUE_SIZE | The bits of Blue in | 0 |
+ | | the color buffer | |
+ | EGL_ALPHA_SIZE | The bits of Alpha in | 0 |
+ | | the color buffer | |
+ | | buffer data | |
+ | EGL_NATIVE_BUFFER_USAGE_ANDROID | The usage bits of | 0 |
+ | | the buffer data | |
+ +---------------------------------+----------------------+---------------+
+ Table aaa. Legal attributes for eglCreateNativeClientBufferANDROID
+ <attrib_list> parameter.
+
+ The maximum width and height may depend on the amount of available memory,
+ which may also depend on the format and usage flags. The values of
+ EGL_RED_SIZE, EGL_GREEN_SIZE, and EGL_BLUE_SIZE must be non-zero and
+ correspond to a valid pixel format for the implementation. If EGL_ALPHA_SIZE
+ is non-zero then the combination of all four sizes must correspond to a
+ valid pixel format for the implementation. The
+ EGL_NATIVE_BUFFER_USAGE_ANDROID flag may include any of the following bits:
+
+ EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID: Indicates that the
+ created buffer must have a hardware-protected path to external display
+ sink. If a hardware-protected path is not available, then either don't
+ composite only this buffer (preferred) to the external sink, or (less
+ desirable) do not route the entire composition to the external sink.
+
+ EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID: The buffer will be
+ used to create a renderbuffer. This flag must not be set if
+ EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID is set.
+
+ EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID: The buffer will be used to
+ create a texture. This flag must not be set if
+ EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID is set.
+
+ Errors
+
+ If eglCreateNativeClientBufferANDROID fails, NULL will be returned, no
+ memory will be allocated, and one of the following errors will be
+ generated:
+
+ * If the value of EGL_WIDTH or EGL_HEIGHT is not positive, the error
+ EGL_BAD_PARAMETER is generated.
+
+ * If the combination of the values of EGL_RED_SIZE, EGL_GREEN_SIZE,
+ EGL_BLUE_SIZE, and EGL_ALPHA_SIZE is not a valid pixel format for the
+ EGL implementation, the error EGL_BAD_PARAMETER is generated.
+
+ * If the value of EGL_NATIVE_BUFFER_ANDROID is not a valid combination
+ of gralloc usage flags for the EGL implementation, or is incompatible
+ with the value of EGL_FORMAT, the error EGL_BAD_PARAMETER is
+ Generated.
+
+ * If both the EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID and
+ EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID are set in the value of
+ EGL_NATIVE_BUFFER_USAGE_ANDROID, the error EGL_BAD_PARAMETER is
+ Generated."
+
+Issues
+
+ 1. Should this extension define what combinations of formats and usage flags
+ EGL implementations are required to support?
+
+ RESOLVED: Partially.
+
+ The set of valid color combinations is implementation-specific and may
+ depend on additional EGL extensions, but generally RGB565 and RGBA888 should
+ be supported. The particular valid combinations for a given Android version
+ and implementation should be documented by that version.
+
+ 2. Should there be an eglDestroyNativeClientBufferANDROID to destroy the
+ client buffers created by this extension?
+
+ RESOLVED: No.
+
+ A destroy function would add several complications:
+
+ a) ANativeWindowBuffer is a reference counted object, may be used
+ outside of EGL.
+ b) The same buffer may back multiple EGLImages, though this usage may
+ result in undefined behavior.
+ c) The interactions between the lifetimes of EGLImages and their
+ EGLClientBuffers would become needlessly complex.
+
+ Because ANativeWindowBuffer is a reference counted object, implementations
+ of this extension should ensure the buffer has a lifetime at least as long
+ as a generated EGLImage (via EGL_ANDROID_image_native_buffer). The simplest
+ method is to increment the reference count of the buffer in
+ eglCreateImagKHR, and then decrement it in eglDestroyImageKHR. This should
+ ensure proper lifetime semantics.
+
+Revision History
+
+#2 (Craig Donner, April 15, 2016)
+ - Set color formats and usage bits explicitly using additional attributes,
+ and add value for new token EGL_NATIVE_BUFFER_USAGE_ANDROID.
+
+#1 (Craig Donner, January 19, 2016)
+ - Initial draft.
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index eed14ab..3f69d49 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -1227,6 +1227,8 @@
int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+ } else if (isWindowObscuredLocked(windowHandle)) {
+ outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
}
mTempTouchState.addOrUpdateWindow(
@@ -1264,6 +1266,8 @@
}
if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+ } else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
+ targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
}
// Update hover state.
@@ -1439,6 +1443,7 @@
== InputWindowInfo::TYPE_WALLPAPER) {
mTempTouchState.addOrUpdateWindow(windowHandle,
InputTarget::FLAG_WINDOW_IS_OBSCURED
+ | InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED
| InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0));
}
@@ -1633,6 +1638,27 @@
return false;
}
+
+bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const {
+ int32_t displayId = windowHandle->getInfo()->displayId;
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ size_t numWindows = mWindowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+ if (otherHandle == windowHandle) {
+ break;
+ }
+
+ const InputWindowInfo* otherInfo = otherHandle->getInfo();
+ if (otherInfo->displayId == displayId
+ && otherInfo->visible && !otherInfo->isTrustedOverlay()
+ && otherInfo->overlaps(windowInfo)) {
+ return true;
+ }
+ }
+ return false;
+}
+
String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
const char* targetType) {
@@ -1907,6 +1933,9 @@
if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
}
+ if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) {
+ dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+ }
if (!connection->inputState.trackMotion(motionEntry,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 98355c6..1c054f5 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -89,7 +89,7 @@
/* This flag indicates that the event is being delivered to a foreground application. */
FLAG_FOREGROUND = 1 << 0,
- /* This flag indicates that the target of a MotionEvent is partly or wholly
+ /* This flag indicates that the MotionEvent falls within the area of the target
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
FLAG_WINDOW_IS_OBSCURED = 1 << 1,
@@ -139,6 +139,12 @@
| FLAG_DISPATCH_AS_HOVER_EXIT
| FLAG_DISPATCH_AS_SLIPPERY_EXIT
| FLAG_DISPATCH_AS_SLIPPERY_ENTER,
+
+ /* This flag indicates that the target of a MotionEvent is partly or wholly
+ * obscured by another visible window above it. The motion event should be
+ * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */
+ FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
+
};
// The input channel to be targeted.
@@ -1048,6 +1054,7 @@
const InjectionState* injectionState);
bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
int32_t x, int32_t y) const;
+ bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const;
String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle);
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index fda3ffa..1b913c5 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -36,14 +36,16 @@
}
bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
- return x >= frameLeft && x <= frameRight
- && y >= frameTop && y <= frameBottom;
+ return x >= frameLeft && x < frameRight
+ && y >= frameTop && y < frameBottom;
}
bool InputWindowInfo::isTrustedOverlay() const {
return layoutParamsType == TYPE_INPUT_METHOD
|| layoutParamsType == TYPE_INPUT_METHOD_DIALOG
|| layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
+ || layoutParamsType == TYPE_STATUS_BAR
+ || layoutParamsType == TYPE_NAVIGATION_BAR
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
}
@@ -51,6 +53,11 @@
return layoutParamsFlags & FLAG_SPLIT_TOUCH;
}
+bool InputWindowInfo::overlaps(const InputWindowInfo* other) const {
+ return frameLeft < other->frameRight && frameRight > other->frameLeft
+ && frameTop < other->frameBottom && frameBottom > other->frameTop;
+}
+
// --- InputWindowHandle ---
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index 42457ce..0ac7fce 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -146,6 +146,8 @@
bool isTrustedOverlay() const;
bool supportsSplitTouch() const;
+
+ bool overlaps(const InputWindowInfo* other) const;
};
diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp
index 788def9..005af18 100644
--- a/services/sensorservice/CorrectedGyroSensor.cpp
+++ b/services/sensorservice/CorrectedGyroSensor.cpp
@@ -30,9 +30,7 @@
// ---------------------------------------------------------------------------
CorrectedGyroSensor::CorrectedGyroSensor(sensor_t const* list, size_t count)
- : mSensorDevice(SensorDevice::getInstance()),
- mSensorFusion(SensorFusion::getInstance())
-{
+ : VirtualSensor() {
for (size_t i=0 ; i<count ; i++) {
if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
mGyro = Sensor(list + i);
@@ -40,17 +38,18 @@
}
}
- sensor_t hwSensor;
- hwSensor.name = "Corrected Gyroscope Sensor";
- hwSensor.vendor = "AOSP";
- hwSensor.version = 1;
- hwSensor.handle = '_cgy';
- hwSensor.type = SENSOR_TYPE_GYROSCOPE;
- hwSensor.maxRange = mGyro.getMaxValue();
- hwSensor.resolution = mGyro.getResolution();
- hwSensor.power = mSensorFusion.getPowerUsage();
- hwSensor.minDelay = mGyro.getMinDelay();
- mSensor = Sensor(&hwSensor);
+ const sensor_t sensor = {
+ .name = "Corrected Gyroscope Sensor",
+ .vendor = "AOSP",
+ .version = 1,
+ .handle = '_cgy',
+ .type = SENSOR_TYPE_GYROSCOPE,
+ .maxRange = mGyro.getMaxValue(),
+ .resolution = mGyro.getResolution(),
+ .power = mSensorFusion.getPowerUsage(),
+ .minDelay = mGyro.getMinDelay(),
+ };
+ mSensor = Sensor(&sensor);
}
bool CorrectedGyroSensor::process(sensors_event_t* outEvent,
@@ -78,10 +77,6 @@
return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
}
-const Sensor& CorrectedGyroSensor::getSensor() const {
- return mSensor;
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/CorrectedGyroSensor.h b/services/sensorservice/CorrectedGyroSensor.h
index 3419a8a..68acd43 100644
--- a/services/sensorservice/CorrectedGyroSensor.h
+++ b/services/sensorservice/CorrectedGyroSensor.h
@@ -31,19 +31,14 @@
class SensorDevice;
class SensorFusion;
-class CorrectedGyroSensor : public SensorInterface {
- SensorDevice& mSensorDevice;
- SensorFusion& mSensorFusion;
+class CorrectedGyroSensor : public VirtualSensor {
Sensor mGyro;
- Sensor mSensor;
public:
CorrectedGyroSensor(sensor_t const* list, size_t count);
virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
virtual status_t activate(void* ident, bool enabled) override;
virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
- virtual const Sensor& getSensor() const override;
- virtual bool isVirtual() const override { return true; }
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index 0e80f16..9d8add1 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -29,10 +29,7 @@
namespace android {
// ---------------------------------------------------------------------------
-GravitySensor::GravitySensor(sensor_t const* list, size_t count)
- : mSensorDevice(SensorDevice::getInstance()),
- mSensorFusion(SensorFusion::getInstance())
-{
+GravitySensor::GravitySensor(sensor_t const* list, size_t count) {
for (size_t i=0 ; i<count ; i++) {
if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
mAccelerometer = Sensor(list + i);
@@ -40,17 +37,18 @@
}
}
- sensor_t hwSensor;
- hwSensor.name = "Gravity Sensor";
- hwSensor.vendor = "AOSP";
- hwSensor.version = 3;
- hwSensor.handle = '_grv';
- hwSensor.type = SENSOR_TYPE_GRAVITY;
- hwSensor.maxRange = GRAVITY_EARTH * 2;
- hwSensor.resolution = mAccelerometer.getResolution();
- hwSensor.power = mSensorFusion.getPowerUsage();
- hwSensor.minDelay = mSensorFusion.getMinDelay();
- mSensor = Sensor(&hwSensor);
+ const sensor_t sensor = {
+ .name = "Gravity Sensor",
+ .vendor = "AOSP",
+ .version = 3,
+ .handle = '_grv',
+ .type = SENSOR_TYPE_GRAVITY,
+ .maxRange = GRAVITY_EARTH * 2,
+ .resolution = mAccelerometer.getResolution(),
+ .power = mSensorFusion.getPowerUsage(),
+ .minDelay = mSensorFusion.getMinDelay(),
+ };
+ mSensor = Sensor(&sensor);
}
bool GravitySensor::process(sensors_event_t* outEvent,
@@ -85,10 +83,6 @@
return mSensorFusion.setDelay(FUSION_NOMAG, ident, ns);
}
-const Sensor& GravitySensor::getSensor() const {
- return mSensor;
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h
index f9c0a99..8e33a73 100644
--- a/services/sensorservice/GravitySensor.h
+++ b/services/sensorservice/GravitySensor.h
@@ -31,19 +31,14 @@
class SensorDevice;
class SensorFusion;
-class GravitySensor : public SensorInterface {
- SensorDevice& mSensorDevice;
- SensorFusion& mSensorFusion;
+class GravitySensor : public VirtualSensor {
Sensor mAccelerometer;
- Sensor mSensor;
public:
GravitySensor(sensor_t const* list, size_t count);
virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
virtual status_t activate(void* ident, bool enabled) override;
virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
- virtual const Sensor& getSensor() const override;
- virtual bool isVirtual() const override { return true; }
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp
index 04beced..d1cd732 100644
--- a/services/sensorservice/LinearAccelerationSensor.cpp
+++ b/services/sensorservice/LinearAccelerationSensor.cpp
@@ -29,22 +29,21 @@
namespace android {
// ---------------------------------------------------------------------------
-LinearAccelerationSensor::LinearAccelerationSensor(sensor_t const* list, size_t count)
- : mSensorDevice(SensorDevice::getInstance()),
- mGravitySensor(list, count)
-{
+LinearAccelerationSensor::LinearAccelerationSensor(sensor_t const* list, size_t count) :
+ mGravitySensor(list, count) {
const Sensor &gsensor = mGravitySensor.getSensor();
- sensor_t hwSensor;
- hwSensor.name = "Linear Acceleration Sensor";
- hwSensor.vendor = "AOSP";
- hwSensor.version = gsensor.getVersion();
- hwSensor.handle = '_lin';
- hwSensor.type = SENSOR_TYPE_LINEAR_ACCELERATION;
- hwSensor.maxRange = gsensor.getMaxValue();
- hwSensor.resolution = gsensor.getResolution();
- hwSensor.power = gsensor.getPowerUsage();
- hwSensor.minDelay = gsensor.getMinDelay();
- mSensor = Sensor(&hwSensor);
+ const sensor_t sensor = {
+ .name = "Linear Acceleration Sensor",
+ .vendor = "AOSP",
+ .version = gsensor.getVersion(),
+ .handle = '_lin',
+ .type = SENSOR_TYPE_LINEAR_ACCELERATION,
+ .maxRange = gsensor.getMaxValue(),
+ .resolution = gsensor.getResolution(),
+ .power = gsensor.getPowerUsage(),
+ .minDelay = gsensor.getMinDelay(),
+ };
+ mSensor = Sensor(&sensor);
}
bool LinearAccelerationSensor::process(sensors_event_t* outEvent,
@@ -70,10 +69,6 @@
return mGravitySensor.setDelay(ident, handle, ns);
}
-const Sensor& LinearAccelerationSensor::getSensor() const {
- return mSensor;
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/LinearAccelerationSensor.h b/services/sensorservice/LinearAccelerationSensor.h
index 6b8027b..428baa6 100644
--- a/services/sensorservice/LinearAccelerationSensor.h
+++ b/services/sensorservice/LinearAccelerationSensor.h
@@ -32,10 +32,8 @@
class SensorDevice;
class SensorFusion;
-class LinearAccelerationSensor : public SensorInterface {
- SensorDevice& mSensorDevice;
+class LinearAccelerationSensor : public VirtualSensor {
GravitySensor mGravitySensor;
- Sensor mSensor;
virtual bool process(sensors_event_t* outEvent,
const sensors_event_t& event);
@@ -43,8 +41,6 @@
LinearAccelerationSensor(sensor_t const* list, size_t count);
virtual status_t activate(void* ident, bool enabled) override;
virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
- virtual const Sensor& getSensor() const override;
- virtual bool isVirtual() const override { return true; }
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp
index 20b49be..ea5dbc9 100644
--- a/services/sensorservice/OrientationSensor.cpp
+++ b/services/sensorservice/OrientationSensor.cpp
@@ -29,24 +29,19 @@
namespace android {
// ---------------------------------------------------------------------------
-OrientationSensor::OrientationSensor()
- : mSensorDevice(SensorDevice::getInstance()),
- mSensorFusion(SensorFusion::getInstance())
-{
- // FIXME: instead of using the SensorFusion code, we should use
- // the SENSOR_TYPE_ROTATION_VECTOR instead. This way we could use the
- // HAL's implementation.
- sensor_t hwSensor;
- hwSensor.name = "Orientation Sensor";
- hwSensor.vendor = "AOSP";
- hwSensor.version = 1;
- hwSensor.handle = '_ypr';
- hwSensor.type = SENSOR_TYPE_ORIENTATION;
- hwSensor.maxRange = 360.0f;
- hwSensor.resolution = 1.0f/256.0f; // FIXME: real value here
- hwSensor.power = mSensorFusion.getPowerUsage();
- hwSensor.minDelay = mSensorFusion.getMinDelay();
- mSensor = Sensor(&hwSensor);
+OrientationSensor::OrientationSensor() {
+ const sensor_t sensor = {
+ .name = "Orientation Sensor",
+ .vendor = "AOSP",
+ .version = 1,
+ .handle = '_ypr',
+ .type = SENSOR_TYPE_ORIENTATION,
+ .maxRange = 360.0f,
+ .resolution = 1.0f/256.0f, // FIXME: real value here
+ .power = mSensorFusion.getPowerUsage(),
+ .minDelay = mSensorFusion.getMinDelay(),
+ };
+ mSensor = Sensor(&sensor);
}
bool OrientationSensor::process(sensors_event_t* outEvent,
@@ -84,10 +79,6 @@
return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
}
-const Sensor& OrientationSensor::getSensor() const {
- return mSensor;
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/OrientationSensor.h b/services/sensorservice/OrientationSensor.h
index 644a774..30ff226 100644
--- a/services/sensorservice/OrientationSensor.h
+++ b/services/sensorservice/OrientationSensor.h
@@ -31,18 +31,12 @@
class SensorDevice;
class SensorFusion;
-class OrientationSensor : public SensorInterface {
- SensorDevice& mSensorDevice;
- SensorFusion& mSensorFusion;
- Sensor mSensor;
-
+class OrientationSensor : public VirtualSensor {
public:
OrientationSensor();
virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
virtual status_t activate(void* ident, bool enabled) override;
virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
- virtual const Sensor& getSensor() const override;
- virtual bool isVirtual() const override { return true; }
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index 5a40ef9..7b00f4d 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -27,22 +27,20 @@
namespace android {
// ---------------------------------------------------------------------------
-RotationVectorSensor::RotationVectorSensor(int mode)
- : mSensorDevice(SensorDevice::getInstance()),
- mSensorFusion(SensorFusion::getInstance()),
- mMode(mode)
-{
- sensor_t hwSensor;
- hwSensor.name = getSensorName();
- hwSensor.vendor = "AOSP";
- hwSensor.version = 3;
- hwSensor.handle = getSensorToken();
- hwSensor.type = getSensorType();
- hwSensor.maxRange = 1;
- hwSensor.resolution = 1.0f / (1<<24);
- hwSensor.power = mSensorFusion.getPowerUsage();
- hwSensor.minDelay = mSensorFusion.getMinDelay();
- mSensor = Sensor(&hwSensor);
+RotationVectorSensor::RotationVectorSensor(int mode) :
+ mMode(mode) {
+ const sensor_t sensor = {
+ .name = getSensorName(),
+ .vendor = "AOSP",
+ .version = 3,
+ .handle = getSensorToken(),
+ .type = getSensorType(),
+ .maxRange = 1,
+ .resolution = 1.0f / (1<<24),
+ .power = mSensorFusion.getPowerUsage(),
+ .minDelay = mSensorFusion.getMinDelay(),
+ };
+ mSensor = Sensor(&sensor);
}
bool RotationVectorSensor::process(sensors_event_t* outEvent,
@@ -72,10 +70,6 @@
return mSensorFusion.setDelay(mMode, ident, ns);
}
-const Sensor& RotationVectorSensor::getSensor() const {
- return mSensor;
-}
-
int RotationVectorSensor::getSensorType() const {
switch(mMode) {
case FUSION_9AXIS:
@@ -120,21 +114,19 @@
// ---------------------------------------------------------------------------
-GyroDriftSensor::GyroDriftSensor()
- : mSensorDevice(SensorDevice::getInstance()),
- mSensorFusion(SensorFusion::getInstance())
-{
- sensor_t hwSensor;
- hwSensor.name = "Gyroscope Bias (debug)";
- hwSensor.vendor = "AOSP";
- hwSensor.version = 1;
- hwSensor.handle = '_gbs';
- hwSensor.type = SENSOR_TYPE_ACCELEROMETER;
- hwSensor.maxRange = 1;
- hwSensor.resolution = 1.0f / (1<<24);
- hwSensor.power = mSensorFusion.getPowerUsage();
- hwSensor.minDelay = mSensorFusion.getMinDelay();
- mSensor = Sensor(&hwSensor);
+GyroDriftSensor::GyroDriftSensor() {
+ const sensor_t sensor = {
+ .name = "Gyroscope Bias (debug)",
+ .vendor = "AOSP",
+ .version = 1,
+ .handle = '_gbs',
+ .type = SENSOR_TYPE_ACCELEROMETER,
+ .maxRange = 1,
+ .resolution = 1.0f / (1<<24),
+ .power = mSensorFusion.getPowerUsage(),
+ .minDelay = mSensorFusion.getMinDelay(),
+ };
+ mSensor = Sensor(&sensor);
}
bool GyroDriftSensor::process(sensors_event_t* outEvent,
@@ -163,10 +155,6 @@
return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
}
-const Sensor& GyroDriftSensor::getSensor() const {
- return mSensor;
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
index 5dba0d5..3cc2248 100644
--- a/services/sensorservice/RotationVectorSensor.h
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -32,23 +32,18 @@
namespace android {
// ---------------------------------------------------------------------------
-class RotationVectorSensor : public SensorInterface {
- SensorDevice& mSensorDevice;
- SensorFusion& mSensorFusion;
- int mMode;
- Sensor mSensor;
-
- int getSensorType() const;
- const char* getSensorName() const ;
- int getSensorToken() const ;
-
+class RotationVectorSensor : public VirtualSensor {
public:
RotationVectorSensor(int mode = FUSION_9AXIS);
virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
virtual status_t activate(void* ident, bool enabled) override;
virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
- virtual const Sensor& getSensor() const override;
- virtual bool isVirtual() const override { return true; }
+
+protected:
+ const int mMode;
+ int getSensorType() const;
+ const char* getSensorName() const ;
+ int getSensorToken() const ;
};
class GameRotationVectorSensor : public RotationVectorSensor {
@@ -61,18 +56,12 @@
GeoMagRotationVectorSensor() : RotationVectorSensor(FUSION_NOGYRO) {}
};
-class GyroDriftSensor : public SensorInterface {
- SensorDevice& mSensorDevice;
- SensorFusion& mSensorFusion;
- Sensor mSensor;
-
+class GyroDriftSensor : public VirtualSensor {
public:
GyroDriftSensor();
virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
virtual status_t activate(void* ident, bool enabled) override;
virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
- virtual const Sensor& getSensor() const override;
- virtual bool isVirtual() const override { return true; }
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index ca26535..c1e1bad 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -21,6 +21,7 @@
#include "vec.h"
#include "SensorEventConnection.h"
+#include "SensorDevice.h"
namespace android {
@@ -88,15 +89,14 @@
bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
Mutex::Autolock _l(mConnectionLock);
- if (!canAccessSensor(mService->getSensorFromHandle(handle),
- "Tried adding", mOpPackageName)) {
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si == nullptr ||
+ !canAccessSensor(si->getSensor(), "Tried adding", mOpPackageName) ||
+ mSensorInfo.indexOfKey(handle) >= 0) {
return false;
}
- if (mSensorInfo.indexOfKey(handle) < 0) {
- mSensorInfo.add(handle, FlushInfo());
- return true;
- }
- return false;
+ mSensorInfo.add(handle, FlushInfo());
+ return true;
}
bool SensorService::SensorEventConnection::removeSensor(int32_t handle) {
@@ -121,7 +121,8 @@
Mutex::Autolock _l(mConnectionLock);
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
const int handle = mSensorInfo.keyAt(i);
- if (mService->getSensorFromHandle(handle).getReportingMode() == AREPORTING_MODE_ONE_SHOT) {
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si != nullptr && si->getSensor().getReportingMode() == AREPORTING_MODE_ONE_SHOT) {
return true;
}
}
@@ -164,9 +165,9 @@
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()) {
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si != nullptr && si->getSensor().isWakeUpSensor()) {
looper_flags |= ALOOPER_EVENT_INPUT;
- break;
}
}
@@ -385,11 +386,16 @@
// Loop through all the sensors for this connection and check if there are any pending
// flush complete events to be sent.
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
+ const int handle = mSensorInfo.keyAt(i);
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si == nullptr) {
+ continue;
+ }
+
FlushInfo& flushInfo = mSensorInfo.editValueAt(i);
while (flushInfo.mPendingFlushEventsToSend > 0) {
- const int sensor_handle = mSensorInfo.keyAt(i);
- flushCompleteEvent.meta_data.sensor = sensor_handle;
- bool wakeUpSensor = mService->getSensorFromHandle(sensor_handle).isWakeUpSensor();
+ flushCompleteEvent.meta_data.sensor = handle;
+ bool wakeUpSensor = si->getSensor().isWakeUpSensor();
if (wakeUpSensor) {
++mWakeLockRefCount;
flushCompleteEvent.flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
@@ -544,37 +550,41 @@
unsigned char buf[sizeof(sensors_event_t)];
ssize_t numBytesRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
{
- Mutex::Autolock _l(mConnectionLock);
- 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);
+ Mutex::Autolock _l(mConnectionLock);
+ 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;
+ }
+ sensors_event_t sensor_event;
+ memcpy(&sensor_event, buf, sizeof(sensors_event_t));
+ sp<SensorInterface> si =
+ mService->getSensorInterfaceFromHandle(sensor_event.sensor);
+ if (si == nullptr) {
+ return 1;
+ }
+
+ SensorDevice& dev(SensorDevice::getInstance());
+ sensor_event.type = si->getSensor().getType();
+ dev.injectSensorData(&sensor_event);
#if DEBUG_CONNECTIONS
- ++mEventsReceived;
+ ++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;
- }
+ } 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;
+ mTotalAcksReceived += numAcks;
#endif
} else {
// Read error, reset wakelock refcount.
@@ -601,7 +611,11 @@
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));
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(mSensorInfo.keyAt(i));
+ if (si == nullptr) {
+ continue;
+ }
+ const Sensor& sensor = si->getSensor();
if (sensor.getFifoReservedEventCount() == sensor.getFifoMaxEventCount()) {
// Each sensor has a reserved fifo. Sum up the fifo sizes for all wake up sensors and
// non wake_up sensors.
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index bb2a8a2..cb24229 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -14,24 +14,30 @@
* limitations under the License.
*/
+#include "SensorInterface.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+
#include <stdint.h>
#include <sys/types.h>
-#include "SensorInterface.h"
-
namespace android {
// ---------------------------------------------------------------------------
-SensorInterface::~SensorInterface()
-{
+namespace {
+const sensor_t DUMMY_SENSOR = {
+ .name = "", .vendor = "", .stringType = "", .requiredPermission = ""};
+} //unnamed namespace
+
+BaseSensor::BaseSensor(const sensor_t& sensor) :
+ mSensorDevice(SensorDevice::getInstance()),
+ mSensor(&sensor, mSensorDevice.getHalDeviceVersion()) {
}
// ---------------------------------------------------------------------------
-HardwareSensor::HardwareSensor(const sensor_t& sensor)
- : mSensorDevice(SensorDevice::getInstance()),
- mSensor(&sensor, mSensorDevice.getHalDeviceVersion())
-{
+HardwareSensor::HardwareSensor(const sensor_t& sensor):
+ BaseSensor(sensor) {
}
HardwareSensor::~HardwareSensor() {
@@ -65,10 +71,9 @@
mSensorDevice.autoDisable(ident, handle);
}
-const Sensor& HardwareSensor::getSensor() const {
- return mSensor;
+VirtualSensor::VirtualSensor() :
+ BaseSensor(DUMMY_SENSOR), mSensorFusion(SensorFusion::getInstance()) {
}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index 06cca75..d1cee41 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -17,52 +17,61 @@
#ifndef ANDROID_SENSOR_INTERFACE_H
#define ANDROID_SENSOR_INTERFACE_H
-#include <stdint.h>
-#include <sys/types.h>
-
#include <gui/Sensor.h>
-
-#include "SensorDevice.h"
+#include <utils/RefBase.h>
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
+class SensorDevice;
+class SensorFusion;
-class SensorInterface {
+class SensorInterface : public VirtualLightRefBase {
public:
- virtual ~SensorInterface();
+ virtual ~SensorInterface() {}
virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) = 0;
virtual status_t activate(void* ident, bool enabled) = 0;
virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
+ virtual status_t batch(void* ident, int handle, int /*flags*/, int64_t samplingPeriodNs,
+ int64_t maxBatchReportLatencyNs) = 0;
+
+ virtual status_t flush(void* /*ident*/, int /*handle*/) = 0;
+
+ virtual const Sensor& getSensor() const = 0;
+ virtual bool isVirtual() const = 0;
+ virtual void autoDisable(void* /*ident*/, int /*handle*/) = 0;
+};
+
+class BaseSensor : public SensorInterface {
+public:
+ BaseSensor(const sensor_t& sensor);
// Not all sensors need to support batching.
- virtual status_t batch(void* ident, int handle, int /*flags*/, int64_t samplingPeriodNs,
- int64_t maxBatchReportLatencyNs) {
+ virtual status_t batch(void* ident, int handle, int, int64_t samplingPeriodNs,
+ int64_t maxBatchReportLatencyNs) override {
if (maxBatchReportLatencyNs == 0) {
return setDelay(ident, handle, samplingPeriodNs);
}
return -EINVAL;
}
- virtual status_t flush(void* /*ident*/, int /*handle*/) {
+ virtual status_t flush(void* /*ident*/, int /*handle*/) override {
return -EINVAL;
}
- virtual const Sensor& getSensor() const = 0;
- virtual bool isVirtual() const = 0;
- virtual void autoDisable(void* /*ident*/, int /*handle*/) { }
+ virtual const Sensor& getSensor() const override { return mSensor; }
+ virtual void autoDisable(void* /*ident*/, int /*handle*/) override { }
+protected:
+ SensorDevice& mSensorDevice;
+ Sensor mSensor;
};
// ---------------------------------------------------------------------------
-class HardwareSensor : public SensorInterface
-{
- SensorDevice& mSensorDevice;
- Sensor mSensor;
-
+class HardwareSensor : public BaseSensor {
public:
HardwareSensor(const sensor_t& sensor);
@@ -76,11 +85,19 @@
int64_t maxBatchReportLatencyNs) override;
virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
virtual status_t flush(void* ident, int handle) override;
- virtual const Sensor& getSensor() const override;
virtual bool isVirtual() const override { return false; }
virtual void autoDisable(void *ident, int handle) override;
};
+class VirtualSensor : public BaseSensor
+{
+public:
+ VirtualSensor();
+ virtual bool isVirtual() const override { return true; }
+protected:
+ SensorFusion& mSensorFusion;
+};
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index f28acd2..c23e21f 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -41,7 +41,6 @@
std::lock_guard<std::mutex> lk(mLock);
auto entry = mHandleMap.find(handle);
if (entry != mHandleMap.end()) {
- mRecycle.push_back(entry->second.si);
mHandleMap.erase(entry);
return true;
}
@@ -54,14 +53,9 @@
mNonSensor.getName());
}
-const Sensor& SensorList::get(int handle) const {
- return getOne<const Sensor&>(
- handle, [] (const Entry& e) -> const Sensor& {return e.si->getSensor();}, mNonSensor);
-}
-
-SensorInterface* SensorList::getInterface(int handle) const {
- return getOne<SensorInterface *>(
- handle, [] (const Entry& e) -> SensorInterface* {return e.si;}, nullptr);
+sp<SensorInterface> SensorList::getInterface(int handle) const {
+ return getOne<sp<SensorInterface>>(
+ handle, [] (const Entry& e) -> sp<SensorInterface> {return e.si;}, nullptr);
}
@@ -182,15 +176,6 @@
}
SensorList::~SensorList() {
- // from this point on no one should access anything in SensorList
- mLock.lock();
- for (auto i : mRecycle) {
- delete i;
- }
- for (auto&& i : mHandleMap) {
- delete i.second.si;
- }
- // the lock will eventually get destructed, there is no guarantee after that.
}
} // namespace SensorServiceUtil
diff --git a/services/sensorservice/SensorList.h b/services/sensorservice/SensorList.h
index 3fe73cc..ffde619 100644
--- a/services/sensorservice/SensorList.h
+++ b/services/sensorservice/SensorList.h
@@ -46,6 +46,9 @@
// After SensorInterface * is added into SensorList, it can be assumed that SensorList own the
// object it pointed to and the object should not be released elsewhere.
bool add(int handle, SensorInterface* si, bool isForDebug = false, bool isVirtual = false);
+
+ // After a handle is removed, the object that SensorInterface * pointing to may get deleted if
+ // no more sp<> of the same object exist.
bool remove(int handle);
inline bool hasAnySensor() const { return mHandleMap.size() > 0;}
@@ -57,8 +60,7 @@
const Vector<Sensor> getVirtualSensors() const;
String8 getName(int handle) const;
- const Sensor& get(int handle) const;
- SensorInterface* getInterface(int handle) const;
+ sp<SensorInterface> getInterface(int handle) const;
bool isNewHandle(int handle) const;
// Iterate through Sensor in sensor list and perform operation f on each Sensor object.
@@ -80,8 +82,7 @@
virtual ~SensorList();
private:
struct Entry {
- //TODO: use sp<> here
- SensorInterface * const si;
+ sp<SensorInterface> si;
const bool isForDebug;
const bool isVirtual;
Entry(SensorInterface* si_, bool debug_, bool virtual_) :
@@ -108,7 +109,6 @@
mutable std::mutex mLock;
std::map<int, Entry> mHandleMap;
std::unordered_set<int> mUsedHandle;
- std::vector<SensorInterface *> mRecycle;
};
template <typename TF>
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index f334e29..b7a8740 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -33,6 +33,7 @@
#include "OrientationSensor.h"
#include "RotationVectorSensor.h"
#include "SensorFusion.h"
+#include "SensorInterface.h"
#include "SensorService.h"
#include "SensorEventConnection.h"
@@ -141,8 +142,8 @@
!needLinearAcceleration, true);
// virtual debugging sensors are not for user
- registerSensor( new CorrectedGyroSensor(list, count), false, true);
- registerSensor( new GyroDriftSensor(), false, true);
+ registerSensor( new CorrectedGyroSensor(list, count), true, true);
+ registerSensor( new GyroDriftSensor(), true, true);
}
if (hasAccel && hasGyro) {
@@ -408,10 +409,10 @@
handle = buffer[i].meta_data.sensor;
}
if (connection->hasSensor(handle)) {
- SensorInterface* si = mSensors.getInterface(handle);
+ sp<SensorInterface> si = getSensorInterfaceFromHandle(handle);
// If this buffer has an event from a one_shot sensor and this connection is registered
// for this particular one_shot sensor, try cleaning up the connection.
- if (si != NULL &&
+ if (si != nullptr &&
si->getSensor().getReportingMode() == AREPORTING_MODE_ONE_SHOT) {
si->autoDisable(connection.get(), handle);
cleanupWithoutDisableLocked(connection, handle);
@@ -477,8 +478,7 @@
// handle virtual sensors
if (count && vcount) {
sensors_event_t const * const event = mSensorEventBuffer;
- const size_t activeVirtualSensorCount = mActiveVirtualSensors.size();
- if (activeVirtualSensorCount) {
+ if (!mActiveVirtualSensors.empty()) {
size_t k = 0;
SensorFusion& fusion(SensorFusion::getInstance());
if (fusion.isEnabled()) {
@@ -487,7 +487,7 @@
}
}
for (size_t i=0 ; i<size_t(count) && k<minBufferSize ; i++) {
- for (size_t j=0 ; j<activeVirtualSensorCount ; j++) {
+ for (int handle : mActiveVirtualSensors) {
if (count + k >= minBufferSize) {
ALOGE("buffer too small to hold all events: "
"count=%zd, k=%zu, size=%zu",
@@ -495,7 +495,12 @@
break;
}
sensors_event_t out;
- SensorInterface* si = mActiveVirtualSensors.valueAt(j);
+ sp<SensorInterface> si = mSensors.getInterface(handle);
+ if (si == nullptr) {
+ ALOGE("handle %d is not an valid virtual sensor", handle);
+ continue;
+ }
+
if (si->process(&out, event[i])) {
mSensorEventBuffer[count + k] = out;
k++;
@@ -698,8 +703,8 @@
}
bool SensorService::isVirtualSensor(int handle) const {
- SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
- return sensor != NULL && sensor->isVirtual();
+ sp<SensorInterface> sensor = getSensorInterfaceFromHandle(handle);
+ return sensor != nullptr && sensor->isVirtual();
}
bool SensorService::isWakeUpSensorEvent(const sensors_event_t& event) const {
@@ -707,8 +712,8 @@
if (event.type == SENSOR_TYPE_META_DATA) {
handle = event.meta_data.sensor;
}
- SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
- return sensor != NULL && sensor->getSensor().isWakeUpSensor();
+ sp<SensorInterface> sensor = getSensorInterfaceFromHandle(handle);
+ return sensor != nullptr && sensor->getSensor().isWakeUpSensor();
}
Vector<Sensor> SensorService::getSensorList(const String16& opPackageName) {
@@ -735,14 +740,15 @@
Vector<Sensor> accessibleSensorList;
mSensors.forEachSensor(
[&opPackageName, &accessibleSensorList] (const Sensor& sensor) -> bool {
- if (sensor.isDynamicSensor() &&
- canAccessSensor(sensor, "getDynamicSensorList", opPackageName)) {
- accessibleSensorList.add(sensor);
- } else {
- ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32,
- sensor.getName().string(),
- sensor.getRequiredPermission().string(),
- sensor.getRequiredAppOp());
+ if (sensor.isDynamicSensor()) {
+ if (canAccessSensor(sensor, "getDynamicSensorList", opPackageName)) {
+ accessibleSensorList.add(sensor);
+ } else {
+ ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32,
+ sensor.getName().string(),
+ sensor.getRequiredPermission().string(),
+ sensor.getRequiredAppOp());
+ }
}
return true;
});
@@ -805,10 +811,11 @@
int handle = mActiveSensors.keyAt(i);
if (c->hasSensor(handle)) {
ALOGD_IF(DEBUG_CONNECTIONS, "%zu: disabling handle=0x%08x", i, handle);
- SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
- ALOGE_IF(!sensor, "mSensorMap[handle=0x%08x] is null!", handle);
- if (sensor) {
+ sp<SensorInterface> sensor = getSensorInterfaceFromHandle(handle);
+ if (sensor != nullptr) {
sensor->activate(c, false);
+ } else {
+ ALOGE("sensor interface of handle=0x%08x is null!", handle);
}
c->removeSensor(handle);
}
@@ -821,7 +828,7 @@
if (rec && rec->removeConnection(connection)) {
ALOGD_IF(DEBUG_CONNECTIONS, "... and it was the last connection");
mActiveSensors.removeItemsAt(i, 1);
- mActiveVirtualSensors.removeItem(handle);
+ mActiveVirtualSensors.erase(handle);
delete rec;
size--;
} else {
@@ -836,13 +843,10 @@
}
}
-SensorInterface* SensorService::getSensorInterfaceFromHandle(int handle) const {
+sp<SensorInterface> SensorService::getSensorInterfaceFromHandle(int handle) const {
return mSensors.getInterface(handle);
}
-const Sensor& SensorService::getSensorFromHandle(int handle) const {
- return mSensors.get(handle);
-}
status_t SensorService::enable(const sp<SensorEventConnection>& connection,
int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
@@ -850,12 +854,9 @@
if (mInitCheck != NO_ERROR)
return mInitCheck;
- SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
- if (sensor == NULL) {
- return BAD_VALUE;
- }
-
- if (!canAccessSensor(sensor->getSensor(), "Tried enabling", opPackageName)) {
+ sp<SensorInterface> sensor = getSensorInterfaceFromHandle(handle);
+ if (sensor == nullptr ||
+ !canAccessSensor(sensor->getSensor(), "Tried enabling", opPackageName)) {
return BAD_VALUE;
}
@@ -870,7 +871,7 @@
rec = new SensorRecord(connection);
mActiveSensors.add(handle, rec);
if (sensor->isVirtual()) {
- mActiveVirtualSensors.add(handle, sensor);
+ mActiveVirtualSensors.emplace(handle);
}
} else {
if (rec->addConnection(connection)) {
@@ -983,8 +984,8 @@
Mutex::Autolock _l(mLock);
status_t err = cleanupWithoutDisableLocked(connection, handle);
if (err == NO_ERROR) {
- SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
- err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
+ sp<SensorInterface> sensor = getSensorInterfaceFromHandle(handle);
+ err = sensor != nullptr ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
}
if (err == NO_ERROR) {
@@ -1024,7 +1025,7 @@
// see if this sensor becomes inactive
if (rec->removeConnection(connection)) {
mActiveSensors.removeItem(handle);
- mActiveVirtualSensors.removeItem(handle);
+ mActiveVirtualSensors.erase(handle);
delete rec;
}
return NO_ERROR;
@@ -1037,11 +1038,9 @@
if (mInitCheck != NO_ERROR)
return mInitCheck;
- SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
- if (!sensor)
- return BAD_VALUE;
-
- if (!canAccessSensor(sensor->getSensor(), "Tried configuring", opPackageName)) {
+ sp<SensorInterface> sensor = getSensorInterfaceFromHandle(handle);
+ if (sensor == nullptr ||
+ !canAccessSensor(sensor->getSensor(), "Tried configuring", opPackageName)) {
return BAD_VALUE;
}
@@ -1066,7 +1065,10 @@
// Loop through all sensors for this connection and call flush on each of them.
for (size_t i = 0; i < connection->mSensorInfo.size(); ++i) {
const int handle = connection->mSensorInfo.keyAt(i);
- SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
+ sp<SensorInterface> sensor = getSensorInterfaceFromHandle(handle);
+ if (sensor == nullptr) {
+ continue;
+ }
if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ONE_SHOT) {
ALOGE("flush called on a one-shot sensor");
err = INVALID_OPERATION;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index e535339..6473edb 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -17,27 +17,25 @@
#ifndef ANDROID_SENSOR_SERVICE_H
#define ANDROID_SENSOR_SERVICE_H
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Vector.h>
-#include <utils/SortedVector.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-#include <utils/AndroidThreads.h>
-#include <utils/RefBase.h>
-#include <utils/Looper.h>
-#include <utils/String8.h>
+#include "SensorList.h"
#include <binder/BinderService.h>
-
-#include <gui/Sensor.h>
-#include <gui/BitTube.h>
+#include <cutils/compiler.h>
#include <gui/ISensorServer.h>
#include <gui/ISensorEventConnection.h>
+#include <gui/Sensor.h>
-#include "SensorInterface.h"
-#include "SensorList.h"
+#include <utils/AndroidThreads.h>
+#include <utils/KeyedVector.h>
+#include <utils/Looper.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unordered_set>
#if __clang__
// Clang warns about SensorEventConnection::dump hiding BBinder::dump. The cause isn't fixable
@@ -57,6 +55,7 @@
namespace android {
// ---------------------------------------------------------------------------
+class SensorInterface;
class SensorService :
public BinderService<SensorService>,
@@ -138,7 +137,6 @@
};
static const char* WAKE_LOCK_NAME;
-
static char const* getServiceName() ANDROID_API { return "sensorservice"; }
SensorService() ANDROID_API;
virtual ~SensorService();
@@ -160,8 +158,7 @@
static int getNumEventsForSensorType(int sensor_event_type);
String8 getSensorName(int handle) const;
bool isVirtualSensor(int handle) const;
- SensorInterface* getSensorInterfaceFromHandle(int handle) const;
- const Sensor& getSensorFromHandle(int handle) const;
+ sp<SensorInterface> getSensorInterfaceFromHandle(int handle) const;
bool isWakeUpSensor(int type) const;
void recordLastValueLocked(sensors_event_t const* buffer, size_t count);
static void sortEventBuffer(sensors_event_t* buffer, size_t count);
@@ -216,12 +213,14 @@
// Socket buffersize used to initialize BitTube. This size depends on whether batching is
// supported or not.
- uint32_t mSocketBufferSize; sp<Looper> mLooper; sp<SensorEventAckReceiver> mAckReceiver;
+ uint32_t mSocketBufferSize;
+ sp<Looper> mLooper;
+ sp<SensorEventAckReceiver> mAckReceiver;
// protected by mLock
mutable Mutex mLock;
DefaultKeyedVector<int, SensorRecord*> mActiveSensors;
- DefaultKeyedVector<int, SensorInterface*> mActiveVirtualSensors;
+ std::unordered_set<int> mActiveVirtualSensors;
SortedVector< wp<SensorEventConnection> > mActiveConnections;
bool mWakeLockAcquired;
sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 4cf9370..5ba387d 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -15,7 +15,6 @@
*/
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-//#define LOG_NDEBUG 0
// This is needed for stdint.h to define INT64_MAX in C++
#define __STDC_LIMIT_MACROS
@@ -34,21 +33,12 @@
#include "DispSync.h"
#include "EventLog/EventLog.h"
-#include <algorithm>
-
-using std::max;
-using std::min;
-
namespace android {
// Setting this to true enables verbose tracing that can be used to debug
// vsync event model or phase issues.
static const bool kTraceDetailedInfo = false;
-// Setting this to true adds a zero-phase tracer for correlating with hardware
-// vsync events
-static const bool kEnableZeroPhaseTracer = false;
-
// This is the threshold used to determine when hardware vsync events are
// needed to re-synchronize the software vsync model with the hardware. The
// error metric used is the mean of the squared difference between each
@@ -59,36 +49,28 @@
// vsync event.
static const int64_t kPresentTimeOffset = PRESENT_TIME_OFFSET_FROM_VSYNC_NS;
-#undef LOG_TAG
-#define LOG_TAG "DispSyncThread"
class DispSyncThread: public Thread {
public:
- DispSyncThread(const char* name):
- mName(name),
+ DispSyncThread():
mStop(false),
mPeriod(0),
mPhase(0),
mReferenceTime(0),
- mWakeupLatency(0),
- mFrameNumber(0) {}
+ mWakeupLatency(0) {
+ }
virtual ~DispSyncThread() {}
void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
- if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
mPeriod = period;
mPhase = phase;
mReferenceTime = referenceTime;
- ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
- " mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
- ns2us(mPhase), ns2us(mReferenceTime));
mCond.signal();
}
void stop() {
- if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
mStop = true;
mCond.signal();
@@ -107,12 +89,6 @@
{ // Scope for lock
Mutex::Autolock lock(mMutex);
- if (kTraceDetailedInfo) {
- ATRACE_INT64("DispSync:Frame", mFrameNumber);
- }
- ALOGV("[%s] Frame %" PRId64, mName, mFrameNumber);
- ++mFrameNumber;
-
if (mStop) {
return false;
}
@@ -133,9 +109,6 @@
bool isWakeup = false;
if (now < targetTime) {
- ALOGV("[%s] Waiting until %" PRId64, mName,
- ns2us(targetTime));
- if (kTraceDetailedInfo) ATRACE_NAME("DispSync waiting");
err = mCond.waitRelative(mMutex, targetTime - now);
if (err == TIMED_OUT) {
@@ -149,15 +122,15 @@
now = systemTime(SYSTEM_TIME_MONOTONIC);
- // Don't correct by more than 1.5 ms
- static const nsecs_t kMaxWakeupLatency = us2ns(1500);
-
if (isWakeup) {
mWakeupLatency = ((mWakeupLatency * 63) +
(now - targetTime)) / 64;
- mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
+ if (mWakeupLatency > 500000) {
+ // Don't correct by more than 500 us
+ mWakeupLatency = 500000;
+ }
if (kTraceDetailedInfo) {
- ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
+ ATRACE_INT64("DispSync:WakeupLat", now - nextEventTime);
ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);
}
}
@@ -173,9 +146,7 @@
return false;
}
- status_t addEventListener(const char* name, nsecs_t phase,
- const sp<DispSync::Callback>& callback) {
- if (kTraceDetailedInfo) ATRACE_CALL();
+ status_t addEventListener(nsecs_t phase, const sp<DispSync::Callback>& callback) {
Mutex::Autolock lock(mMutex);
for (size_t i = 0; i < mEventListeners.size(); i++) {
@@ -185,14 +156,15 @@
}
EventListener listener;
- listener.mName = name;
listener.mPhase = phase;
listener.mCallback = callback;
// We want to allow the firstmost future event to fire without
- // allowing any past events to fire
- listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase -
- mWakeupLatency;
+ // allowing any past events to fire. Because
+ // computeListenerNextEventTimeLocked filters out events within a half
+ // a period of the last event time, we need to initialize the last
+ // event time to a half a period in the past.
+ listener.mLastEventTime = systemTime(SYSTEM_TIME_MONOTONIC) - mPeriod / 2;
mEventListeners.push(listener);
@@ -202,7 +174,6 @@
}
status_t removeEventListener(const sp<DispSync::Callback>& callback) {
- if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
for (size_t i = 0; i < mEventListeners.size(); i++) {
@@ -218,7 +189,6 @@
// This method is only here to handle the kIgnorePresentFences case.
bool hasAnyEventListeners() {
- if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
return !mEventListeners.empty();
}
@@ -226,7 +196,6 @@
private:
struct EventListener {
- const char* mName;
nsecs_t mPhase;
nsecs_t mLastEventTime;
sp<DispSync::Callback> mCallback;
@@ -238,8 +207,6 @@
};
nsecs_t computeNextEventTimeLocked(nsecs_t now) {
- if (kTraceDetailedInfo) ATRACE_CALL();
- ALOGV("[%s] computeNextEventTimeLocked", mName);
nsecs_t nextEventTime = INT64_MAX;
for (size_t i = 0; i < mEventListeners.size(); i++) {
nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
@@ -250,28 +217,21 @@
}
}
- ALOGV("[%s] nextEventTime = %" PRId64, mName, ns2us(nextEventTime));
return nextEventTime;
}
Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
- if (kTraceDetailedInfo) ATRACE_CALL();
- ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName,
- ns2us(now));
-
Vector<CallbackInvocation> callbackInvocations;
- nsecs_t onePeriodAgo = now - mPeriod;
+ nsecs_t ref = now - mPeriod;
for (size_t i = 0; i < mEventListeners.size(); i++) {
nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
- onePeriodAgo);
+ ref);
if (t < now) {
CallbackInvocation ci;
ci.mCallback = mEventListeners[i].mCallback;
ci.mEventTime = t;
- ALOGV("[%s] [%s] Preparing to fire", mName,
- mEventListeners[i].mName);
callbackInvocations.push(ci);
mEventListeners.editItemAt(i).mLastEventTime = t;
}
@@ -281,67 +241,29 @@
}
nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener,
- nsecs_t baseTime) {
- if (kTraceDetailedInfo) ATRACE_CALL();
- ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")",
- mName, listener.mName, ns2us(baseTime));
+ nsecs_t ref) {
- nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency;
- ALOGV("[%s] lastEventTime: %" PRId64, mName, ns2us(lastEventTime));
- if (baseTime < lastEventTime) {
- baseTime = lastEventTime;
- ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName,
- ns2us(baseTime));
+ nsecs_t lastEventTime = listener.mLastEventTime;
+ if (ref < lastEventTime) {
+ ref = lastEventTime;
}
- baseTime -= mReferenceTime;
- ALOGV("[%s] Relative baseTime = %" PRId64, mName, ns2us(baseTime));
- nsecs_t phase = mPhase + listener.mPhase;
- ALOGV("[%s] Phase = %" PRId64, mName, ns2us(phase));
- baseTime -= phase;
- ALOGV("[%s] baseTime - phase = %" PRId64, mName, ns2us(baseTime));
+ nsecs_t phase = mReferenceTime + mPhase + listener.mPhase;
+ nsecs_t t = (((ref - phase) / mPeriod) + 1) * mPeriod + phase;
- // If our previous time is before the reference (because the reference
- // has since been updated), the division by mPeriod will truncate
- // towards zero instead of computing the floor. Since in all cases
- // before the reference we want the next time to be effectively now, we
- // set baseTime to -mPeriod so that numPeriods will be -1.
- // When we add 1 and the phase, we will be at the correct event time for
- // this period.
- if (baseTime < 0) {
- ALOGV("[%s] Correcting negative baseTime", mName);
- baseTime = -mPeriod;
- }
-
- nsecs_t numPeriods = baseTime / mPeriod;
- ALOGV("[%s] numPeriods = %" PRId64, mName, numPeriods);
- nsecs_t t = (numPeriods + 1) * mPeriod + phase;
- ALOGV("[%s] t = %" PRId64, mName, ns2us(t));
- t += mReferenceTime;
- ALOGV("[%s] Absolute t = %" PRId64, mName, ns2us(t));
-
- // Check that it's been slightly more than half a period since the last
- // event so that we don't accidentally fall into double-rate vsyncs
- if (t - listener.mLastEventTime < (3 * mPeriod / 5)) {
+ if (t - listener.mLastEventTime < mPeriod / 2) {
t += mPeriod;
- ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
}
- t -= mWakeupLatency;
- ALOGV("[%s] Corrected for wakeup latency -> %" PRId64, mName, ns2us(t));
-
return t;
}
void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {
- if (kTraceDetailedInfo) ATRACE_CALL();
for (size_t i = 0; i < callbacks.size(); i++) {
callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
}
}
- const char* const mName;
-
bool mStop;
nsecs_t mPeriod;
@@ -349,17 +271,12 @@
nsecs_t mReferenceTime;
nsecs_t mWakeupLatency;
- int64_t mFrameNumber;
-
Vector<EventListener> mEventListeners;
Mutex mMutex;
Condition mCond;
};
-#undef LOG_TAG
-#define LOG_TAG "DispSync"
-
class ZeroPhaseTracer : public DispSync::Callback {
public:
ZeroPhaseTracer() : mParity(false) {}
@@ -373,10 +290,9 @@
bool mParity;
};
-DispSync::DispSync(const char* name) :
- mName(name),
+DispSync::DispSync() :
mRefreshSkipCount(0),
- mThread(new DispSyncThread(name)) {
+ mThread(new DispSyncThread()) {
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
@@ -389,8 +305,8 @@
// Even if we're just ignoring the fences, the zero-phase tracing is
// not needed because any time there is an event registered we will
// turn on the HW vsync events.
- if (!kIgnorePresentFences && kEnableZeroPhaseTracer) {
- addEventListener("ZeroPhaseTracer", 0, new ZeroPhaseTracer());
+ if (!kIgnorePresentFences) {
+ addEventListener(0, new ZeroPhaseTracer());
}
}
}
@@ -435,7 +351,7 @@
void DispSync::beginResync() {
Mutex::Autolock lock(mMutex);
- ALOGV("[%s] beginResync", mName);
+
mModelUpdated = false;
mNumResyncSamples = 0;
}
@@ -443,17 +359,11 @@
bool DispSync::addResyncSample(nsecs_t timestamp) {
Mutex::Autolock lock(mMutex);
- ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp));
-
size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
mResyncSamples[idx] = timestamp;
if (mNumResyncSamples == 0) {
mPhase = 0;
mReferenceTime = timestamp;
- ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
- "mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
- ns2us(mReferenceTime));
- mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}
if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
@@ -477,21 +387,17 @@
return mThread->hasAnyEventListeners();
}
- // Check against kErrorThreshold / 2 to add some hysteresis before having to
- // resync again
- bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2);
- ALOGV("[%s] addResyncSample returning %s", mName,
- modelLocked ? "locked" : "unlocked");
- return !modelLocked;
+ return !mModelUpdated || mError > kErrorThreshold;
}
void DispSync::endResync() {
}
-status_t DispSync::addEventListener(const char* name, nsecs_t phase,
+status_t DispSync::addEventListener(nsecs_t phase,
const sp<Callback>& callback) {
+
Mutex::Autolock lock(mMutex);
- return mThread->addEventListener(name, phase, callback);
+ return mThread->addEventListener(phase, callback);
}
void DispSync::setRefreshSkipCount(int count) {
@@ -521,32 +427,20 @@
}
void DispSync::updateModelLocked() {
- ALOGV("[%s] updateModelLocked %zu", mName, mNumResyncSamples);
if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
- ALOGV("[%s] Computing...", mName);
nsecs_t durationSum = 0;
- nsecs_t minDuration = INT64_MAX;
- nsecs_t maxDuration = 0;
for (size_t i = 1; i < mNumResyncSamples; i++) {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
- nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev];
- durationSum += duration;
- minDuration = min(minDuration, duration);
- maxDuration = max(maxDuration, duration);
+ durationSum += mResyncSamples[idx] - mResyncSamples[prev];
}
- // Exclude the min and max from the average
- durationSum -= minDuration + maxDuration;
- mPeriod = durationSum / (mNumResyncSamples - 3);
-
- ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
+ mPeriod = durationSum / (mNumResyncSamples - 1);
double sampleAvgX = 0;
double sampleAvgY = 0;
double scale = 2.0 * M_PI / double(mPeriod);
- // Intentionally skip the first sample
- for (size_t i = 1; i < mNumResyncSamples; i++) {
+ for (size_t i = 0; i < mNumResyncSamples; i++) {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
nsecs_t sample = mResyncSamples[idx] - mReferenceTime;
double samplePhase = double(sample % mPeriod) * scale;
@@ -554,21 +448,18 @@
sampleAvgY += sin(samplePhase);
}
- sampleAvgX /= double(mNumResyncSamples - 1);
- sampleAvgY /= double(mNumResyncSamples - 1);
+ sampleAvgX /= double(mNumResyncSamples);
+ sampleAvgY /= double(mNumResyncSamples);
mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);
- ALOGV("[%s] mPhase = %" PRId64, mName, ns2us(mPhase));
-
- if (mPhase < -(mPeriod / 2)) {
+ if (mPhase < 0) {
mPhase += mPeriod;
- ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
}
if (kTraceDetailedInfo) {
ATRACE_INT64("DispSync:Period", mPeriod);
- ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
+ ATRACE_INT64("DispSync:Phase", mPhase);
}
// Artificially inflate the period if requested.
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 537c81b..a8524b9 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -26,8 +26,11 @@
namespace android {
// Ignore present (retire) fences if the device doesn't have support for the
-// sync framework
-#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK)
+// sync framework, or if all phase offsets are zero. The latter is useful
+// because it allows us to avoid resync bursts on devices that don't need
+// phase-offset VSYNC events.
+#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK) || \
+ (VSYNC_EVENT_PHASE_OFFSET_NS == 0 && SF_VSYNC_EVENT_PHASE_OFFSET_NS == 0)
static const bool kIgnorePresentFences = true;
#else
static const bool kIgnorePresentFences = false;
@@ -61,7 +64,7 @@
virtual void onDispSyncEvent(nsecs_t when) = 0;
};
- DispSync(const char* name);
+ DispSync();
~DispSync();
// reset clears the resync samples and error value.
@@ -111,8 +114,7 @@
// given phase offset from the hardware vsync events. The callback is
// called from a separate thread and it should return reasonably quickly
// (i.e. within a few hundred microseconds).
- status_t addEventListener(const char* name, nsecs_t phase,
- const sp<Callback>& callback);
+ status_t addEventListener(nsecs_t phase, const sp<Callback>& callback);
// removeEventListener removes an already-registered event callback. Once
// this method returns that callback will no longer be called by the
@@ -135,12 +137,10 @@
void resetErrorLocked();
enum { MAX_RESYNC_SAMPLES = 32 };
- enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 };
+ enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 };
enum { NUM_PRESENT_SAMPLES = 8 };
enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
- const char* const mName;
-
// mPeriod is the computed period of the modeled vsync events in
// nanoseconds.
nsecs_t mPeriod;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
index d37fcb2..4afd8a2 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
@@ -926,16 +926,19 @@
protected:
HWCTYPE* const mLayerList;
HWCTYPE* mCurrentLayer;
- Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer) { }
+ Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer),
+ mIndex(0) { }
inline HWCTYPE const * getLayer() const { return mCurrentLayer; }
inline HWCTYPE* getLayer() { return mCurrentLayer; }
virtual ~Iterable() { }
+ size_t mIndex;
private:
// returns a copy of ourselves
virtual HWComposer::HWCLayer* dup() {
return new CONCRETE( static_cast<const CONCRETE&>(*this) );
}
virtual status_t setLayer(size_t index) {
+ mIndex = index;
mCurrentLayer = &mLayerList[index];
return NO_ERROR;
}
@@ -948,8 +951,12 @@
class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> {
struct hwc_composer_device_1* mHwc;
public:
- HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer)
- : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc) { }
+ HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer,
+ Vector<Region>* visibleRegions,
+ Vector<Region>* surfaceDamageRegions)
+ : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc),
+ mVisibleRegions(visibleRegions),
+ mSurfaceDamageRegions(surfaceDamageRegions) {}
virtual int32_t getCompositionType() const {
return getLayer()->compositionType;
@@ -1037,9 +1044,10 @@
}
virtual void setVisibleRegionScreen(const Region& reg) {
hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen;
- mVisibleRegion = reg;
+ mVisibleRegions->editItemAt(mIndex) = reg;
visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(
- mVisibleRegion.getArray(&visibleRegion.numRects));
+ mVisibleRegions->itemAt(mIndex).getArray(
+ &visibleRegion.numRects));
}
virtual void setSurfaceDamage(const Region& reg) {
if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) {
@@ -1053,9 +1061,10 @@
surfaceDamage.rects = NULL;
return;
}
- mSurfaceDamage = reg;
+ mSurfaceDamageRegions->editItemAt(mIndex) = reg;
surfaceDamage.rects = reinterpret_cast<hwc_rect_t const *>(
- mSurfaceDamage.getArray(&surfaceDamage.numRects));
+ mSurfaceDamageRegions->itemAt(mIndex).getArray(
+ &surfaceDamage.numRects));
}
virtual void setSidebandStream(const sp<NativeHandle>& stream) {
ALOG_ASSERT(stream->handle() != NULL);
@@ -1081,11 +1090,10 @@
}
protected:
- // We need to hold "copies" of these for memory management purposes. The
- // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
- // internally doesn't copy the memory unless one of the copies is modified.
- Region mVisibleRegion;
- Region mSurfaceDamage;
+ // Pointers to the vectors of Region backing-memory held in DisplayData.
+ // Only the Region at mIndex corresponds to this Layer.
+ Vector<Region>* mVisibleRegions;
+ Vector<Region>* mSurfaceDamageRegions;
};
/*
@@ -1095,11 +1103,18 @@
if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
return LayerListIterator();
}
- const DisplayData& disp(mDisplayData[id]);
+ DisplayData& disp(mDisplayData[id]);
if (!mHwc || !disp.list || index > disp.list->numHwLayers) {
return LayerListIterator();
}
- return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers), index);
+ if (disp.visibleRegions.size() < disp.list->numHwLayers) {
+ disp.visibleRegions.resize(disp.list->numHwLayers);
+ }
+ if (disp.surfaceDamageRegions.size() < disp.list->numHwLayers) {
+ disp.surfaceDamageRegions.resize(disp.list->numHwLayers);
+ }
+ return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers,
+ &disp.visibleRegions, &disp.surfaceDamageRegions), index);
}
/*
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
index f5f7d77..c861817 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
@@ -346,6 +346,13 @@
// protected by mEventControlLock
int32_t events;
+
+ // We need to hold "copies" of these for memory management purposes. The
+ // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
+ // internally doesn't copy the memory unless one of the copies is
+ // modified.
+ Vector<Region> visibleRegions;
+ Vector<Region> surfaceDamageRegions;
};
sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index dd88adb..f760200 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -44,9 +44,8 @@
return;
}
-EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger)
+EventThread::EventThread(const sp<VSyncSource>& src)
: mVSyncSource(src),
- mFlinger(flinger),
mUseSoftwareVSync(false),
mVsyncEnabled(false),
mDebugVsyncEnabled(false),
@@ -127,9 +126,6 @@
void EventThread::requestNextVsync(
const sp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
-
- mFlinger.resyncWithRateLimit();
-
if (connection->count < 0) {
connection->count = 0;
mCondition.broadcast();
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 34654fa..9ba179a 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -77,7 +77,7 @@
public:
- EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger);
+ EventThread(const sp<VSyncSource>& src);
sp<Connection> createEventConnection() const;
status_t registerDisplayEventConnection(const sp<Connection>& connection);
@@ -116,7 +116,6 @@
// constants
sp<VSyncSource> mVSyncSource;
PowerHAL mPowerHAL;
- SurfaceFlinger& mFlinger;
mutable Mutex mLock;
mutable Condition mCondition;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a2c0462..1803ee5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -75,6 +75,7 @@
mSidebandStreamChanged(false),
mCurrentTransform(0),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+ mOverrideScalingMode(-1),
mCurrentOpacity(true),
mCurrentFrameNumber(0),
mRefreshPending(false),
@@ -1244,7 +1245,7 @@
}
bool Layer::isFixedSize() const {
- return mCurrentScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
}
bool Layer::isCropped() const {
@@ -1309,16 +1310,16 @@
mPendingStates.push_back(mCurrentState);
}
-void Layer::popPendingState() {
- auto oldFlags = mCurrentState.flags;
- mCurrentState = mPendingStates[0];
- mCurrentState.flags = (oldFlags & ~mCurrentState.mask) |
- (mCurrentState.flags & mCurrentState.mask);
+void Layer::popPendingState(State* stateToCommit) {
+ auto oldFlags = stateToCommit->flags;
+ *stateToCommit = mPendingStates[0];
+ stateToCommit->flags = (oldFlags & ~stateToCommit->mask) |
+ (stateToCommit->flags & stateToCommit->mask);
mPendingStates.removeAt(0);
}
-bool Layer::applyPendingStates() {
+bool Layer::applyPendingStates(State* stateToCommit) {
bool stateUpdateAvailable = false;
while (!mPendingStates.empty()) {
if (mPendingStates[0].handle != nullptr) {
@@ -1327,7 +1328,7 @@
// will be visually wrong, but it should keep us from getting
// into too much trouble.
ALOGE("[%s] No local sync point found", mName.string());
- popPendingState();
+ popPendingState(stateToCommit);
stateUpdateAvailable = true;
continue;
}
@@ -1345,7 +1346,7 @@
if (mRemoteSyncPoints.front()->frameIsAvailable()) {
// Apply the state update
- popPendingState();
+ popPendingState(stateToCommit);
stateUpdateAvailable = true;
// Signal our end of the sync point and then dispose of it
@@ -1355,7 +1356,7 @@
break;
}
} else {
- popPendingState();
+ popPendingState(stateToCommit);
stateUpdateAvailable = true;
}
}
@@ -1385,12 +1386,12 @@
ATRACE_CALL();
pushPendingState();
- if (!applyPendingStates()) {
+ Layer::State c = getCurrentState();
+ if (!applyPendingStates(&c)) {
return 0;
}
const Layer::State& s(getDrawingState());
- const Layer::State& c(getCurrentState());
const bool sizeChanged = (c.requested.w != s.requested.w) ||
(c.requested.h != s.requested.h);
@@ -1403,7 +1404,8 @@
" requested={ wh={%4u,%4u} }}\n"
" drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} }}\n",
- this, getName().string(), mCurrentTransform, mCurrentScalingMode,
+ this, getName().string(), mCurrentTransform,
+ getEffectiveScalingMode(),
c.active.w, c.active.h,
c.crop.left,
c.crop.top,
@@ -1454,8 +1456,7 @@
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
- Layer::State& editCurrentState(getCurrentState());
- editCurrentState.active = c.requested;
+ c.active = c.requested;
}
if (s.active != c.active) {
@@ -1475,12 +1476,12 @@
}
// Commit the transaction
- commitTransaction();
+ commitTransaction(c);
return flags;
}
-void Layer::commitTransaction() {
- mDrawingState = mCurrentState;
+void Layer::commitTransaction(const State& stateToCommit) {
+ mDrawingState = stateToCommit;
}
uint32_t Layer::getTransactionFlags(uint32_t flags) {
@@ -1581,6 +1582,20 @@
return true;
}
+bool Layer::setOverrideScalingMode(int32_t scalingMode) {
+ if (scalingMode == mOverrideScalingMode)
+ return false;
+ mOverrideScalingMode = scalingMode;
+ return true;
+}
+
+uint32_t Layer::getEffectiveScalingMode() const {
+ if (mOverrideScalingMode >= 0) {
+ return mOverrideScalingMode;
+ }
+ return mCurrentScalingMode;
+}
+
bool Layer::setLayerStack(uint32_t layerStack) {
if (mCurrentState.layerStack == layerStack)
return false;
@@ -1739,14 +1754,17 @@
bool& recomputeVisibleRegions;
bool stickyTransformSet;
const char* name;
+ int32_t overrideScalingMode;
Reject(Layer::State& front, Layer::State& current,
bool& recomputeVisibleRegions, bool stickySet,
- const char* name)
+ const char* name,
+ int32_t overrideScalingMode)
: front(front), current(current),
recomputeVisibleRegions(recomputeVisibleRegions),
stickyTransformSet(stickySet),
- name(name) {
+ name(name),
+ overrideScalingMode(overrideScalingMode) {
}
virtual bool reject(const sp<GraphicBuffer>& buf,
@@ -1764,7 +1782,9 @@
swap(bufWidth, bufHeight);
}
- bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ int actualScalingMode = overrideScalingMode >= 0 ?
+ overrideScalingMode : item.mScalingMode;
+ bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
if (front.active != front.requested) {
if (isFixedSize ||
@@ -1840,7 +1860,8 @@
};
Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
- getProducerStickyTransform() != 0, mName.string());
+ getProducerStickyTransform() != 0, mName.string(),
+ mOverrideScalingMode);
// Check all of our local sync points to ensure that all transactions
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1d73b43..7d085a4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -160,6 +160,7 @@
bool setFinalCrop(const Rect& crop);
bool setLayerStack(uint32_t layerStack);
void deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber);
+ bool setOverrideScalingMode(int32_t overrideScalingMode);
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
@@ -431,7 +432,7 @@
virtual void onFrameReplaced(const BufferItem& item) override;
virtual void onSidebandStreamChanged() override;
- void commitTransaction();
+ void commitTransaction(const State& stateToCommit);
// needsLinearFiltering - true if this surface's state requires filtering
bool needsFiltering(const sp<const DisplayDevice>& hw) const;
@@ -500,8 +501,13 @@
bool addSyncPoint(const std::shared_ptr<SyncPoint>& point);
void pushPendingState();
- void popPendingState();
- bool applyPendingStates();
+ void popPendingState(State* stateToCommit);
+ bool applyPendingStates(State* stateToCommit);
+
+ // Returns mCurrentScaling mode (originating from the
+ // Client) or mOverrideScalingMode mode (originating from
+ // the Surface Controller) if set.
+ uint32_t getEffectiveScalingMode() const;
public:
void notifyAvailableFrames();
private:
@@ -536,6 +542,8 @@
Rect mCurrentCrop;
uint32_t mCurrentTransform;
uint32_t mCurrentScalingMode;
+ // We encode unset as -1.
+ int32_t mOverrideScalingMode;
bool mCurrentOpacity;
std::atomic<uint64_t> mCurrentFrameNumber;
bool mRefreshPending;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a448639..efa32a7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -149,7 +149,6 @@
mLastTransactionTime(0),
mBootFinished(false),
mForceFullDamage(false),
- mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mDaltonize(false),
@@ -332,12 +331,11 @@
class DispSyncSource : public VSyncSource, private DispSync::Callback {
public:
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
- const char* name) :
- mName(name),
+ const char* label) :
mValue(0),
mTraceVsync(traceVsync),
- mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
- mVsyncEventLabel(String8::format("VSYNC-%s", name)),
+ mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
+ mVsyncEventLabel(String8::format("VSYNC-%s", label)),
mDispSync(dispSync),
mCallbackMutex(),
mCallback(),
@@ -350,7 +348,7 @@
virtual void setVSyncEnabled(bool enable) {
Mutex::Autolock lock(mVsyncMutex);
if (enable) {
- status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
+ status_t err = mDispSync->addEventListener(mPhaseOffset,
static_cast<DispSync::Callback*>(this));
if (err != NO_ERROR) {
ALOGE("error registering vsync callback: %s (%d)",
@@ -401,7 +399,7 @@
}
// Add a listener with the new offset
- err = mDispSync->addEventListener(mName, mPhaseOffset,
+ err = mDispSync->addEventListener(mPhaseOffset,
static_cast<DispSync::Callback*>(this));
if (err != NO_ERROR) {
ALOGE("error registering vsync callback: %s (%d)",
@@ -427,8 +425,6 @@
}
}
- const char* const mName;
-
int mValue;
const bool mTraceVsync;
@@ -459,10 +455,10 @@
// start the EventThread
sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
vsyncPhaseOffsetNs, true, "app");
- mEventThread = new EventThread(vsyncSrc, *this);
+ mEventThread = new EventThread(vsyncSrc);
sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
sfVsyncPhaseOffsetNs, true, "sf");
- mSFEventThread = new EventThread(sfVsyncSrc, *this);
+ mSFEventThread = new EventThread(sfVsyncSrc);
mEventQueue.setEventThread(mSFEventThread);
// Get a RenderEngine for the given display / config (can't fail)
@@ -831,13 +827,6 @@
}
}
-void SurfaceFlinger::resyncWithRateLimit() {
- static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
- if (systemTime() - mLastSwapTime > kIgnoreDelay) {
- resyncToHardwareVsync(true);
- }
-}
-
void SurfaceFlinger::onVSyncReceived(int32_t type, nsecs_t timestamp) {
bool needsHwVsync = false;
@@ -2302,6 +2291,11 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
+ if (what & layer_state_t::eOverrideScalingModeChanged) {
+ layer->setOverrideScalingMode(s.overrideScalingMode);
+ // We don't trigger a traversal here because if no other state is
+ // changed, we don't want this to cause any more work
+ }
}
return flags;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 633e956..8c974d0 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -409,11 +409,8 @@
* VSync
*/
void enableHardwareVsync();
- void resyncToHardwareVsync(bool makeAvailable);
void disableHardwareVsync(bool makeUnavailable);
-public:
- void resyncWithRateLimit();
-private:
+ void resyncToHardwareVsync(bool makeAvailable);
/* ------------------------------------------------------------------------
* Debugging & dumpsys
@@ -525,7 +522,7 @@
static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
nsecs_t mFrameBuckets[NUM_BUCKETS];
nsecs_t mTotalTime;
- std::atomic<nsecs_t> mLastSwapTime;
+ nsecs_t mLastSwapTime;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index ea685e7..bc20bbc 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -148,7 +148,6 @@
mLastTransactionTime(0),
mBootFinished(false),
mForceFullDamage(false),
- mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mDaltonize(false),
@@ -330,12 +329,11 @@
class DispSyncSource : public VSyncSource, private DispSync::Callback {
public:
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
- const char* name) :
- mName(name),
+ const char* label) :
mValue(0),
mTraceVsync(traceVsync),
- mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
- mVsyncEventLabel(String8::format("VSYNC-%s", name)),
+ mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
+ mVsyncEventLabel(String8::format("VSYNC-%s", label)),
mDispSync(dispSync),
mCallbackMutex(),
mCallback(),
@@ -348,7 +346,7 @@
virtual void setVSyncEnabled(bool enable) {
Mutex::Autolock lock(mVsyncMutex);
if (enable) {
- status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
+ status_t err = mDispSync->addEventListener(mPhaseOffset,
static_cast<DispSync::Callback*>(this));
if (err != NO_ERROR) {
ALOGE("error registering vsync callback: %s (%d)",
@@ -399,7 +397,7 @@
}
// Add a listener with the new offset
- err = mDispSync->addEventListener(mName, mPhaseOffset,
+ err = mDispSync->addEventListener(mPhaseOffset,
static_cast<DispSync::Callback*>(this));
if (err != NO_ERROR) {
ALOGE("error registering vsync callback: %s (%d)",
@@ -425,8 +423,6 @@
}
}
- const char* const mName;
-
int mValue;
const bool mTraceVsync;
@@ -456,10 +452,10 @@
// start the EventThread
sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
vsyncPhaseOffsetNs, true, "app");
- mEventThread = new EventThread(vsyncSrc, *this);
+ mEventThread = new EventThread(vsyncSrc);
sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
sfVsyncPhaseOffsetNs, true, "sf");
- mSFEventThread = new EventThread(sfVsyncSrc, *this);
+ mSFEventThread = new EventThread(sfVsyncSrc);
mEventQueue.setEventThread(mSFEventThread);
// Initialize the H/W composer object. There may or may not be an
@@ -851,13 +847,6 @@
}
}
-void SurfaceFlinger::resyncWithRateLimit() {
- static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
- if (systemTime() - mLastSwapTime > kIgnoreDelay) {
- resyncToHardwareVsync(true);
- }
-}
-
void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
bool needsHwVsync = false;
@@ -2327,6 +2316,11 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
+ if (what & layer_state_t::eOverrideScalingModeChanged) {
+ layer->setOverrideScalingMode(s.overrideScalingMode);
+ // We don't trigger a traversal here because if no other state is
+ // changed, we don't want this to cause any more work
+ }
}
return flags;
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index d7cb899..320fddb 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -459,4 +459,61 @@
}
}
+TEST_F(LayerUpdateTest, DeferredTransactionTest) {
+ sp<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before anything");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel( 32, 32, 63, 63, 195);
+ sc->checkPixel( 96, 96, 195, 63, 63);
+ sc->checkPixel(160, 160, 63, 63, 195);
+ }
+
+ // set up two deferred transactions on different frames
+ SurfaceComposerClient::openGlobalTransaction();
+ ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75));
+ mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(),
+ mSyncSurfaceControl->getSurface()->getNextFrameNumber());
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+ SurfaceComposerClient::openGlobalTransaction();
+ ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128,128));
+ mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(),
+ mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+ {
+ SCOPED_TRACE("before any trigger");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel( 32, 32, 63, 63, 195);
+ sc->checkPixel( 96, 96, 195, 63, 63);
+ sc->checkPixel(160, 160, 63, 63, 195);
+ }
+
+ // should trigger the first deferred transaction, but not the second one
+ fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ {
+ SCOPED_TRACE("after first trigger");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel( 32, 32, 63, 63, 195);
+ sc->checkPixel( 96, 96, 162, 63, 96);
+ sc->checkPixel(160, 160, 63, 63, 195);
+ }
+
+ // should show up immediately since it's not deferred
+ SurfaceComposerClient::openGlobalTransaction();
+ ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0));
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+ // trigger the second deferred transaction
+ fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ {
+ SCOPED_TRACE("after second trigger");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel( 32, 32, 63, 63, 195);
+ sc->checkPixel( 96, 96, 63, 63, 195);
+ sc->checkPixel(160, 160, 195, 63, 63);
+ }
+}
+
}