Merge "SurfaceFlinger: EventThread: Fix Vsync array size."
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 38b0b24..8e6998f 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -285,7 +285,7 @@
run_command("CHECKIN MEMINFO", 30, "dumpsys", "meminfo", "--checkin", NULL);
run_command("CHECKIN NETSTATS", 30, "dumpsys", "netstats", "--checkin", NULL);
run_command("CHECKIN PROCSTATS", 30, "dumpsys", "procstats", "-c", NULL);
- run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "--c", NULL);
+ run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "-c", NULL);
printf("========================================================\n");
printf("== Running Application Activities\n");
diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h
index 98b450c..5bf9acb 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/include/gui/BufferItemConsumer.h
@@ -71,7 +71,8 @@
//
// If waitForFence is true, and the acquired BufferItem has a valid fence object,
// acquireBuffer will wait on the fence with no timeout before returning.
- status_t acquireBuffer(BufferItem *item, bool waitForFence = true);
+ status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen,
+ bool waitForFence = true);
// Returns an acquired buffer to the queue, allowing it to be reused. Since
// only a fixed number of buffers may be acquired at a time, old buffers
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 766fa0f..0143be3 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -39,7 +39,7 @@
enum { NUM_BUFFER_SLOTS = 32 };
enum { NO_CONNECTED_API = 0 };
enum { INVALID_BUFFER_SLOT = -1 };
- enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE };
+ enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE, PRESENT_LATER };
// When in async mode we reserve two slots in order to guarantee that the
// producer and consumer can run asynchronously.
@@ -284,7 +284,13 @@
// acquired then the BufferItem::mGraphicBuffer field of buffer is set to
// NULL and it is assumed that the consumer still holds a reference to the
// buffer.
- status_t acquireBuffer(BufferItem *buffer);
+ //
+ // If presentWhen is nonzero, it indicates the time when the buffer will
+ // be displayed on screen. If the buffer's timestamp is farther in the
+ // future, the buffer won't be acquired, and PRESENT_LATER will be
+ // returned. The presentation time is in nanoseconds, and the time base
+ // is CLOCK_MONOTONIC.
+ status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen);
// releaseBuffer releases a buffer slot from the consumer back to the
// BufferQueue. This may be done while the buffer's contents are still
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index 1d51bc9..42b84cc 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -152,7 +152,8 @@
// initialization that must take place the first time a buffer is assigned
// to a slot. If it is overridden the derived class's implementation must
// call ConsumerBase::acquireBufferLocked.
- virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item);
+ virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item,
+ nsecs_t presentWhen);
// releaseBufferLocked relinquishes control over a buffer, returning that
// control to the BufferQueue.
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 031684e..fbc8840 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -237,7 +237,8 @@
// acquireBufferLocked overrides the ConsumerBase method to update the
// mEglSlots array in addition to the ConsumerBase behavior.
- virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item);
+ virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item,
+ nsecs_t presentWhen);
// releaseBufferLocked overrides the ConsumerBase method to update the
// mEglSlots array in addition to the ConsumerBase.
diff --git a/libs/binder/MemoryBase.cpp b/libs/binder/MemoryBase.cpp
index 5c82330..033066b 100644
--- a/libs/binder/MemoryBase.cpp
+++ b/libs/binder/MemoryBase.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "MemoryBase"
#include <stdlib.h>
#include <stdint.h>
@@ -45,11 +44,3 @@
// ---------------------------------------------------------------------------
}; // namespace android
-
-// Backwards compatibility for libdatabase_sqlcipher (http://b/8253769).
-extern "C" void _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEEij(void*, void*, ssize_t, size_t);
-extern "C" void _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEElj(void* obj, void* h, long o, unsigned int size) {
- _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEEij(obj, h, o, size);
- ALOGW("Using temporary compatibility workaround for usage of MemoryBase "
- "private API. Please fix your application!");
-}
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index ba04bdf..8d86c59 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -47,14 +47,15 @@
mBufferQueue->setConsumerName(name);
}
-status_t BufferItemConsumer::acquireBuffer(BufferItem *item, bool waitForFence) {
+status_t BufferItemConsumer::acquireBuffer(BufferItem *item,
+ nsecs_t presentWhen, bool waitForFence) {
status_t err;
if (!item) return BAD_VALUE;
Mutex::Autolock _l(mMutex);
- err = acquireBufferLocked(item);
+ err = acquireBufferLocked(item, presentWhen);
if (err != OK) {
if (err != NO_BUFFER_AVAILABLE) {
BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 0dab864..8d4b174 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -807,7 +807,7 @@
}
}
-status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
+status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) {
ATRACE_CALL();
Mutex::Autolock _l(mMutex);
@@ -830,38 +830,68 @@
// check if queue is empty
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- if (!mQueue.empty()) {
- Fifo::iterator front(mQueue.begin());
- int buf = front->mBuf;
- *buffer = *front;
- ATRACE_BUFFER_INDEX(buf);
-
- ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
- front->mBuf, front->mFrameNumber,
- front->mGraphicBuffer->handle);
- // if front buffer still being tracked update slot state
- if (stillTracking(front)) {
- mSlots[buf].mAcquireCalled = true;
- mSlots[buf].mNeedsCleanupOnRelease = false;
- mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
- mSlots[buf].mFence = Fence::NO_FENCE;
- }
-
- // If the buffer has previously been acquired by the consumer, set
- // mGraphicBuffer to NULL to avoid unnecessarily remapping this
- // buffer on the consumer side.
- if (buffer->mAcquireCalled) {
- buffer->mGraphicBuffer = NULL;
- }
-
- mQueue.erase(front);
- mDequeueCondition.broadcast();
-
- ATRACE_INT(mConsumerName.string(), mQueue.size());
- } else {
+ if (mQueue.empty()) {
return NO_BUFFER_AVAILABLE;
}
+ Fifo::iterator front(mQueue.begin());
+ int buf = front->mBuf;
+
+ // Compare the buffer's desired presentation time to the predicted
+ // actual display time.
+ //
+ // The "presentWhen" argument indicates when the buffer is expected
+ // to be presented on-screen. If the buffer's desired-present time
+ // is earlier (less) than presentWhen, meaning it'll be displayed
+ // on time or possibly late, we acquire and return it. If we don't want
+ // to display it until after the presentWhen time, we return PRESENT_LATER
+ // without acquiring it.
+ //
+ // To be safe, we don't refuse to acquire the buffer if presentWhen is
+ // more than one second in the future beyond the desired present time
+ // (i.e. we'd be holding the buffer for a really long time).
+ const int MAX_FUTURE_NSEC = 1000000000ULL;
+ nsecs_t desiredPresent = front->mTimestamp;
+ if (presentWhen != 0 && desiredPresent > presentWhen &&
+ desiredPresent - presentWhen < MAX_FUTURE_NSEC)
+ {
+ ALOGV("pts defer: des=%lld when=%lld (%lld) now=%lld",
+ desiredPresent, presentWhen, desiredPresent - presentWhen,
+ systemTime(CLOCK_MONOTONIC));
+ return PRESENT_LATER;
+ }
+ if (presentWhen != 0) {
+ ALOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)",
+ mSlots, buf, mSlots[buf].mFence->getSignalTime(),
+ desiredPresent, presentWhen, desiredPresent - presentWhen);
+ }
+
+ *buffer = *front;
+ ATRACE_BUFFER_INDEX(buf);
+
+ ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
+ front->mBuf, front->mFrameNumber,
+ front->mGraphicBuffer->handle);
+ // if front buffer still being tracked update slot state
+ if (stillTracking(front)) {
+ mSlots[buf].mAcquireCalled = true;
+ mSlots[buf].mNeedsCleanupOnRelease = false;
+ mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+ mSlots[buf].mFence = Fence::NO_FENCE;
+ }
+
+ // If the buffer has previously been acquired by the consumer, set
+ // mGraphicBuffer to NULL to avoid unnecessarily remapping this
+ // buffer on the consumer side.
+ if (buffer->mAcquireCalled) {
+ buffer->mGraphicBuffer = NULL;
+ }
+
+ mQueue.erase(front);
+ mDequeueCondition.broadcast();
+
+ ATRACE_INT(mConsumerName.string(), mQueue.size());
+
return NO_ERROR;
}
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index fd9d153..deb2646 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -182,8 +182,9 @@
}
}
-status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) {
- status_t err = mBufferQueue->acquireBuffer(item);
+status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item,
+ nsecs_t presentWhen) {
+ status_t err = mBufferQueue->acquireBuffer(item, presentWhen);
if (err != NO_ERROR) {
return err;
}
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 123b470..56bc7c6 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -79,7 +79,7 @@
Mutex::Autolock _l(mMutex);
- err = acquireBufferLocked(&b);
+ err = acquireBufferLocked(&b, 0);
if (err != OK) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
return BAD_VALUE;
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 6d29edc..d12083f 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -139,7 +139,7 @@
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = acquireBufferLocked(&item);
+ err = acquireBufferLocked(&item, 0);
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
// We always bind the texture even if we don't update its contents.
@@ -165,8 +165,9 @@
return bindTextureImageLocked();
}
-status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item) {
- status_t err = ConsumerBase::acquireBufferLocked(item);
+status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item,
+ nsecs_t presentWhen) {
+ status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen);
if (err != NO_ERROR) {
return err;
}
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 62d215b..9682987 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -80,7 +80,7 @@
GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
- ASSERT_EQ(OK, mBQ->acquireBuffer(&item));
+ ASSERT_EQ(OK, mBQ->acquireBuffer(&item, 0));
}
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
@@ -90,7 +90,7 @@
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
// Acquire the third buffer, which should fail.
- ASSERT_EQ(INVALID_OPERATION, mBQ->acquireBuffer(&item));
+ ASSERT_EQ(INVALID_OPERATION, mBQ->acquireBuffer(&item, 0));
}
TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) {
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index c02a85f..beaa560 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -1,16 +1,16 @@
-/*
+/*
** Copyright 2007, The Android Open Source Project
**
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
**
- ** http://www.apache.org/licenses/LICENSE-2.0
+ ** http://www.apache.org/licenses/LICENSE-2.0
**
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -56,9 +56,9 @@
*
* For backward compatibility and to facilitate the transition to
* this new naming scheme, the loader will additionally look for:
- *
+ *
* /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so
- *
+ *
*/
ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
@@ -116,14 +116,14 @@
// ----------------------------------------------------------------------------
-Loader::driver_t::driver_t(void* gles)
+Loader::driver_t::driver_t(void* gles)
{
dso[0] = gles;
for (size_t i=1 ; i<NELEM(dso) ; i++)
dso[i] = 0;
}
-Loader::driver_t::~driver_t()
+Loader::driver_t::~driver_t()
{
for (size_t i=0 ; i<NELEM(dso) ; i++) {
if (dso[i]) {
@@ -161,11 +161,17 @@
GLTrace_stop();
}
+static void* load_wrapper(const char* path) {
+ void* so = dlopen(path, RTLD_NOW | RTLD_LOCAL);
+ ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror());
+ return so;
+}
+
void* Loader::open(egl_connection_t* cnx)
{
void* dso;
driver_t* hnd = 0;
-
+
dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2);
if (dso) {
hnd = new driver_t(dso);
@@ -180,7 +186,12 @@
}
LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation");
-
+
+ cnx->libGles2 = load_wrapper("/system/lib/libGLESv2.so");
+ cnx->libGles1 = load_wrapper("/system/lib/libGLESv1_CM.so");
+ LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
+ "couldn't load system OpenGL ES wrapper libraries");
+
return (void*)hnd;
}
@@ -191,16 +202,16 @@
return NO_ERROR;
}
-void Loader::init_api(void* dso,
- char const * const * api,
- __eglMustCastToProperFunctionPointerType* curr,
- getProcAddressType getProcAddress)
+void Loader::init_api(void* dso,
+ char const * const * api,
+ __eglMustCastToProperFunctionPointerType* curr,
+ getProcAddressType getProcAddress)
{
const ssize_t SIZE = 256;
char scrap[SIZE];
while (*api) {
char const * name = *api;
- __eglMustCastToProperFunctionPointerType f =
+ __eglMustCastToProperFunctionPointerType f =
(__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
if (f == NULL) {
// couldn't find the entry-point, use eglGetProcAddress()
@@ -360,7 +371,7 @@
if (mask & EGL) {
getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
- ALOGE_IF(!getProcAddress,
+ ALOGE_IF(!getProcAddress,
"can't find eglGetProcAddress() in %s", driver_absolute_path);
#ifdef SYSTEMUI_PBSIZE_HACK
@@ -398,7 +409,7 @@
char const * const * api = egl_names;
while (*api) {
char const * name = *api;
- __eglMustCastToProperFunctionPointerType f =
+ __eglMustCastToProperFunctionPointerType f =
(__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
if (f == NULL) {
// couldn't find the entry-point, use eglGetProcAddress()
@@ -411,7 +422,7 @@
api++;
}
}
-
+
if (mask & GLESv1_CM) {
init_api(dso, gl_names,
(__eglMustCastToProperFunctionPointerType*)
@@ -425,7 +436,7 @@
&cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
getProcAddress);
}
-
+
return dso;
}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 0358fcc..015740a 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -16,6 +16,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <dlfcn.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@@ -777,6 +778,20 @@
return err;
}
+static __eglMustCastToProperFunctionPointerType findBuiltinGLWrapper(
+ const char* procname) {
+ const egl_connection_t* cnx = &gEGLImpl;
+ void* proc = NULL;
+
+ proc = dlsym(cnx->libGles2, procname);
+ if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
+
+ proc = dlsym(cnx->libGles1, procname);
+ if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
+
+ return NULL;
+}
+
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
{
// eglGetProcAddress() could be the very first function called
@@ -798,6 +813,8 @@
addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap));
if (addr) return addr;
+ addr = findBuiltinGLWrapper(procname);
+ if (addr) return addr;
// this protects accesses to sGLExtentionMap and sGLExtentionSlot
pthread_mutex_lock(&sExtensionMapMutex);
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 1cfe561..b905ea0 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -43,6 +43,9 @@
EGLint major;
EGLint minor;
egl_t egl;
+
+ void* libGles1;
+ void* libGles2;
};
// ----------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 18a1523..2fa5dbd 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -107,13 +107,10 @@
return c;
}
-status_t SensorDevice::resetStateWithoutActuatingHardware(void *ident, int handle)
-{
- if (!mSensorDevice) return NO_INIT;
- Info& info( mActivationCount.editValueFor(handle));
+void SensorDevice::autoDisable(void *ident, int handle) {
+ Info& info( mActivationCount.editValueFor(handle) );
Mutex::Autolock _l(mLock);
info.rates.removeItem(ident);
- return NO_ERROR;
}
status_t SensorDevice::activate(void* ident, int handle, int enabled)
@@ -164,6 +161,15 @@
ALOGE_IF(err, "Error %s sensor %d (%s)",
enabled ? "activating" : "disabling",
handle, strerror(-err));
+
+ if (err != NO_ERROR) {
+ // clean-up on failure
+ if (enabled) {
+ // failure when enabling the sensor
+ Mutex::Autolock _l(mLock);
+ info.rates.removeItem(ident);
+ }
+ }
}
{ // scope for the lock
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index ca67ce2..b50e205 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -56,7 +56,7 @@
ssize_t poll(sensors_event_t* buffer, size_t count);
status_t activate(void* ident, int handle, int enabled);
status_t setDelay(void* ident, int handle, int64_t ns);
- status_t resetStateWithoutActuatingHardware(void *ident, int handle);
+ void autoDisable(void *ident, int handle);
void dump(String8& result);
};
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index cf0a11d..b483b75 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -54,8 +54,8 @@
return mSensorDevice.setDelay(ident, handle, ns);
}
-status_t HardwareSensor::resetStateWithoutActuatingHardware(void *ident, int handle) {
- return mSensorDevice.resetStateWithoutActuatingHardware(ident, handle);
+void HardwareSensor::autoDisable(void *ident, int handle) {
+ mSensorDevice.autoDisable(ident, handle);
}
Sensor HardwareSensor::getSensor() const {
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index 2e709ae..2e14e57 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -40,11 +40,7 @@
virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
virtual Sensor getSensor() const = 0;
virtual bool isVirtual() const = 0;
- virtual status_t resetStateWithoutActuatingHardware(void *ident, int handle) {
- // Override when you want to clean up for sensors which auto disable
- // after trigger, or when enabling sensors fail.
- return INVALID_OPERATION;
- }
+ virtual void autoDisable(void *ident, int handle) { }
};
// ---------------------------------------------------------------------------
@@ -66,7 +62,7 @@
virtual status_t setDelay(void* ident, int handle, int64_t ns);
virtual Sensor getSensor() const;
virtual bool isVirtual() const { return false; }
- virtual status_t resetStateWithoutActuatingHardware(void *ident, int handle);
+ virtual void autoDisable(void *ident, int handle);
};
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 99993ba..e3d2a60 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -274,10 +274,8 @@
if (type == SENSOR_TYPE_SIGNIFICANT_MOTION) {
if (connection->hasSensor(handle)) {
sensor = mSensorMap.valueFor(handle);
- err = sensor ?sensor->resetStateWithoutActuatingHardware(connection.get(), handle)
- : status_t(BAD_VALUE);
- if (err != NO_ERROR) {
- ALOGE("Sensor Inteface: Resetting state failed with err: %d", err);
+ if (sensor != NULL) {
+ sensor->autoDisable(connection.get(), handle);
}
cleanupWithoutDisable(connection, handle);
}
@@ -509,8 +507,12 @@
if (mInitCheck != NO_ERROR)
return mInitCheck;
- Mutex::Autolock _l(mLock);
SensorInterface* sensor = mSensorMap.valueFor(handle);
+ if (sensor == NULL) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
SensorRecord* rec = mActiveSensors.valueFor(handle);
if (rec == 0) {
rec = new SensorRecord(connection);
@@ -546,16 +548,11 @@
handle, connection.get());
}
-
// we are setup, now enable the sensor.
- status_t err = sensor ? sensor->activate(connection.get(), true) : status_t(BAD_VALUE);
-
+ status_t err = sensor->activate(connection.get(), true);
if (err != NO_ERROR) {
- // enable has failed, reset state in SensorDevice.
- status_t resetErr = sensor ? sensor->resetStateWithoutActuatingHardware(connection.get(),
- handle) : status_t(BAD_VALUE);
// enable has failed, reset our state.
- cleanupWithoutDisable(connection, handle);
+ cleanupWithoutDisableLocked(connection, handle);
}
return err;
}
@@ -566,7 +563,8 @@
if (mInitCheck != NO_ERROR)
return mInitCheck;
- status_t err = cleanupWithoutDisable(connection, handle);
+ Mutex::Autolock _l(mLock);
+ status_t err = cleanupWithoutDisableLocked(connection, handle);
if (err == NO_ERROR) {
SensorInterface* sensor = mSensorMap.valueFor(handle);
err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
@@ -574,9 +572,14 @@
return err;
}
-status_t SensorService::cleanupWithoutDisable(const sp<SensorEventConnection>& connection,
- int handle) {
+status_t SensorService::cleanupWithoutDisable(
+ const sp<SensorEventConnection>& connection, int handle) {
Mutex::Autolock _l(mLock);
+ return cleanupWithoutDisableLocked(connection, handle);
+}
+
+status_t SensorService::cleanupWithoutDisableLocked(
+ const sp<SensorEventConnection>& connection, int handle) {
SensorRecord* rec = mActiveSensors.valueFor(handle);
if (rec) {
// see if this connection becomes inactive
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 56b0a3e..69e5dbb 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -115,8 +115,10 @@
static void sortEventBuffer(sensors_event_t* buffer, size_t count);
Sensor registerSensor(SensorInterface* sensor);
Sensor registerVirtualSensor(SensorInterface* sensor);
- status_t cleanupWithoutDisable(const sp<SensorEventConnection>& connection,
- int handle);
+ status_t cleanupWithoutDisable(
+ const sp<SensorEventConnection>& connection, int handle);
+ status_t cleanupWithoutDisableLocked(
+ const sp<SensorEventConnection>& connection, int handle);
void cleanupAutoDisabledSensor(const sp<SensorEventConnection>& connection,
sensors_event_t const* buffer, const int count);
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 10bca38..938459e 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -83,7 +83,7 @@
Mutex::Autolock lock(mMutex);
BufferQueue::BufferItem item;
- status_t err = acquireBufferLocked(&item);
+ status_t err = acquireBufferLocked(&item, 0);
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
outBuffer = mCurrentBuffer;
return NO_ERROR;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 34003b8..f31d650 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -917,11 +917,6 @@
const bool oldOpacity = isOpaque();
sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
- // signal another event if we have more frames pending
- if (android_atomic_dec(&mQueuedFrames) > 1) {
- mFlinger->signalLayerUpdate();
- }
-
struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
Layer::State& front;
Layer::State& current;
@@ -1027,7 +1022,21 @@
Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions);
- if (mSurfaceFlingerConsumer->updateTexImage(&r) != NO_ERROR) {
+ status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r);
+ if (updateResult == BufferQueue::PRESENT_LATER) {
+ // Producer doesn't want buffer to be displayed yet. Signal a
+ // layer update so we check again at the next opportunity.
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ }
+
+ // Decrement the queued-frames count. Signal another event if we
+ // have more frames pending.
+ if (android_atomic_dec(&mQueuedFrames) > 1) {
+ mFlinger->signalLayerUpdate();
+ }
+
+ if (updateResult != NO_ERROR) {
// something happened!
recomputeVisibleRegions = true;
return outDirtyRegion;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 7ac5c60..b181b60 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -50,12 +50,14 @@
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = acquireBufferLocked(&item);
+ err = acquireBufferLocked(&item, computeExpectedPresent());
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
// This variant of updateTexImage does not guarantee that the
// texture is bound, so no need to call glBindTexture.
err = NO_ERROR;
+ } else if (err == BufferQueue::PRESENT_LATER) {
+ // return the error, without logging
} else {
ALOGE("updateTexImage: acquire failed: %s (%d)",
strerror(-err), err);
@@ -99,6 +101,48 @@
return bindTextureImageLocked();
}
+// We need to determine the time when a buffer acquired now will be
+// displayed. This can be calculated:
+// time when previous buffer's actual-present fence was signaled
+// + current display refresh rate * HWC latency
+// + a little extra padding
+//
+// Buffer producers are expected to set their desired presentation time
+// based on choreographer time stamps, which (coming from vsync events)
+// will be slightly later then the actual-present timing. If we get a
+// desired-present time that is unintentionally a hair after the next
+// vsync, we'll hold the frame when we really want to display it. We
+// want to use an expected-presentation time that is slightly late to
+// avoid this sort of edge case.
+nsecs_t SurfaceFlingerConsumer::computeExpectedPresent()
+{
+ // Don't yet have an easy way to get actual buffer flip time for
+ // the specific display, so use the current time. This is typically
+ // 1.3ms past the vsync event time.
+ const nsecs_t prevVsync = systemTime(CLOCK_MONOTONIC);
+
+ // Given a SurfaceFlinger reference, and information about what display
+ // we're destined for, we could query the HWC for the refresh rate. This
+ // could change over time, e.g. we could switch to 24fps for a movie.
+ // For now, assume 60fps.
+ //const nsecs_t vsyncPeriod =
+ // getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ const nsecs_t vsyncPeriod = 16700000;
+
+ // The HWC doesn't currently have a way to report additional latency.
+ // Assume that whatever we submit now will appear on the next flip,
+ // i.e. 1 frame of latency w.r.t. the previous flip.
+ const uint32_t hwcLatency = 1;
+
+ // A little extra padding to compensate for slack between actual vsync
+ // time and vsync event receipt. Currently not needed since we're
+ // using "now" instead of a vsync time.
+ const nsecs_t extraPadding = 0;
+
+ // Total it up.
+ return prevVsync + hwcLatency * vsyncPeriod + extraPadding;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 22eec81..d774c33 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -51,6 +51,9 @@
// See GLConsumer::bindTextureImageLocked().
status_t bindTextureImage();
+
+private:
+ nsecs_t computeExpectedPresent();
};
// ----------------------------------------------------------------------------