summaryrefslogtreecommitdiffstats
path: root/libs/gui
diff options
context:
space:
mode:
Diffstat (limited to 'libs/gui')
-rw-r--r--libs/gui/BufferItem.cpp25
-rw-r--r--libs/gui/BufferItemConsumer.cpp16
-rw-r--r--libs/gui/BufferQueue.cpp8
-rw-r--r--libs/gui/BufferQueueConsumer.cpp272
-rw-r--r--libs/gui/BufferQueueCore.cpp5
-rw-r--r--libs/gui/BufferQueueProducer.cpp44
-rw-r--r--libs/gui/ConsumerBase.cpp40
-rw-r--r--libs/gui/CpuConsumer.cpp19
-rw-r--r--libs/gui/GLConsumer.cpp21
-rw-r--r--libs/gui/IGraphicBufferAlloc.cpp3
-rw-r--r--libs/gui/IGraphicBufferConsumer.cpp16
-rw-r--r--libs/gui/IGraphicBufferProducer.cpp36
-rw-r--r--libs/gui/ISensorServer.cpp32
-rw-r--r--libs/gui/Sensor.cpp39
-rw-r--r--libs/gui/SensorEventQueue.cpp18
-rw-r--r--libs/gui/SensorManager.cpp29
-rw-r--r--libs/gui/Surface.cpp89
-rw-r--r--libs/gui/SurfaceComposerClient.cpp9
-rw-r--r--libs/gui/tests/BufferQueue_test.cpp50
-rw-r--r--libs/gui/tests/DummyConsumer.h27
-rw-r--r--libs/gui/tests/IGraphicBufferProducer_test.cpp2
-rw-r--r--libs/gui/tests/SurfaceTextureClient_test.cpp29
-rw-r--r--libs/gui/tests/SurfaceTextureGLToGL_test.cpp19
-rw-r--r--libs/gui/tests/Surface_test.cpp51
24 files changed, 661 insertions, 238 deletions
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 5793d40..8f64ae0 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -46,15 +46,16 @@ static void addAligned(size_t& size, T /* value */) {
}
size_t BufferItem::getPodSize() const {
- // Must align<8> before writing these fields for this to be correct
size_t size = 0;
addAligned(size, mCrop);
addAligned(size, mTransform);
addAligned(size, mScalingMode);
- addAligned(size, mTimestamp);
+ addAligned(size, mTimestampLo);
+ addAligned(size, mTimestampHi);
addAligned(size, mIsAutoTimestamp);
addAligned(size, mDataSpace);
- addAligned(size, mFrameNumber);
+ addAligned(size, mFrameNumberLo);
+ addAligned(size, mFrameNumberHi);
addAligned(size, mSlot);
addAligned(size, mIsDroppable);
addAligned(size, mAcquireCalled);
@@ -126,9 +127,6 @@ status_t BufferItem::flatten(
if (err) return err;
FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
- // Must align<8> so that getPodSize returns the correct value
- size -= FlattenableUtils::align<8>(buffer);
-
// Check we still have enough space
if (size < getPodSize()) {
return NO_MEMORY;
@@ -137,10 +135,12 @@ status_t BufferItem::flatten(
writeAligned(buffer, size, mCrop);
writeAligned(buffer, size, mTransform);
writeAligned(buffer, size, mScalingMode);
- writeAligned(buffer, size, mTimestamp);
+ writeAligned(buffer, size, mTimestampLo);
+ writeAligned(buffer, size, mTimestampHi);
writeAligned(buffer, size, mIsAutoTimestamp);
writeAligned(buffer, size, mDataSpace);
- writeAligned(buffer, size, mFrameNumber);
+ writeAligned(buffer, size, mFrameNumberLo);
+ writeAligned(buffer, size, mFrameNumberHi);
writeAligned(buffer, size, mSlot);
writeAligned(buffer, size, mIsDroppable);
writeAligned(buffer, size, mAcquireCalled);
@@ -183,9 +183,6 @@ status_t BufferItem::unflatten(
if (err) return err;
FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
- // Must align<8> so that getPodSize returns the correct value
- size -= FlattenableUtils::align<8>(buffer);
-
// Check we still have enough space
if (size < getPodSize()) {
return NO_MEMORY;
@@ -194,10 +191,12 @@ status_t BufferItem::unflatten(
readAligned(buffer, size, mCrop);
readAligned(buffer, size, mTransform);
readAligned(buffer, size, mScalingMode);
- readAligned(buffer, size, mTimestamp);
+ readAligned(buffer, size, mTimestampLo);
+ readAligned(buffer, size, mTimestampHi);
readAligned(buffer, size, mIsAutoTimestamp);
readAligned(buffer, size, mDataSpace);
- readAligned(buffer, size, mFrameNumber);
+ readAligned(buffer, size, mFrameNumberLo);
+ readAligned(buffer, size, mFrameNumberHi);
readAligned(buffer, size, mSlot);
readAligned(buffer, size, mIsDroppable);
readAligned(buffer, size, mAcquireCalled);
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 194121f..578b8d9 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -100,20 +100,4 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item,
return err;
}
-status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
- Mutex::Autolock _l(mMutex);
- return mConsumer->setDefaultBufferSize(w, h);
-}
-
-status_t BufferItemConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
- Mutex::Autolock _l(mMutex);
- return mConsumer->setDefaultBufferFormat(defaultFormat);
-}
-
-status_t BufferItemConsumer::setDefaultBufferDataSpace(
- android_dataspace defaultDataSpace) {
- Mutex::Autolock _l(mMutex);
- return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
-}
-
} // namespace android
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 2fcbaf2..ccbb5a2 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -39,6 +39,14 @@ void BufferQueue::ProxyConsumerListener::onFrameAvailable(
}
}
+void BufferQueue::ProxyConsumerListener::onFrameReplaced(
+ const BufferItem& item) {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != NULL) {
+ listener->onFrameReplaced(item);
+ }
+}
+
void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
sp<ConsumerListener> listener(mConsumerListener.promote());
if (listener != NULL) {
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index c7d5e00..bb3e1b0 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -36,145 +36,170 @@ BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
BufferQueueConsumer::~BufferQueueConsumer() {}
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
- nsecs_t expectedPresent) {
+ nsecs_t expectedPresent, uint64_t maxFrameNumber) {
ATRACE_CALL();
- Mutex::Autolock lock(mCore->mMutex);
- // Check that the consumer doesn't currently have the maximum number of
- // buffers acquired. We allow the max buffer count to be exceeded by one
- // buffer so that the consumer can successfully set up the newly acquired
- // buffer before releasing the old one.
- int numAcquiredBuffers = 0;
- for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
- if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
- ++numAcquiredBuffers;
+ int numDroppedBuffers = 0;
+ sp<IProducerListener> listener;
+ {
+ Mutex::Autolock lock(mCore->mMutex);
+
+ // Check that the consumer doesn't currently have the maximum number of
+ // buffers acquired. We allow the max buffer count to be exceeded by one
+ // buffer so that the consumer can successfully set up the newly acquired
+ // buffer before releasing the old one.
+ int numAcquiredBuffers = 0;
+ for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+ if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
+ ++numAcquiredBuffers;
+ }
+ }
+ if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+ BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
+ numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
+ return INVALID_OPERATION;
}
- }
- if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
- BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
- numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
- return INVALID_OPERATION;
- }
- // Check if the 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 (mCore->mQueue.empty()) {
- return NO_BUFFER_AVAILABLE;
- }
+ // Check if the 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 (mCore->mQueue.empty()) {
+ return NO_BUFFER_AVAILABLE;
+ }
- BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
-
- // If expectedPresent is specified, we may not want to return a buffer yet.
- // If it's specified and there's more than one buffer queued, we may want
- // to drop a buffer.
- if (expectedPresent != 0) {
- const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
-
- // The 'expectedPresent' argument indicates when the buffer is expected
- // to be presented on-screen. If the buffer's desired present time is
- // earlier (less) than expectedPresent -- meaning it will be displayed
- // on time or possibly late if we show it as soon as possible -- we
- // acquire and return it. If we don't want to display it until after the
- // expectedPresent time, we return PRESENT_LATER without acquiring it.
- //
- // To be safe, we don't defer acquisition if expectedPresent is more
- // than one second in the future beyond the desired present time
- // (i.e., we'd be holding the buffer for a long time).
- //
- // NOTE: Code assumes monotonic time values from the system clock
- // are positive.
-
- // Start by checking to see if we can drop frames. We skip this check if
- // the timestamps are being auto-generated by Surface. If the app isn't
- // generating timestamps explicitly, it probably doesn't want frames to
- // be discarded based on them.
- while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
- // If entry[1] is timely, drop entry[0] (and repeat). We apply an
- // additional criterion here: we only drop the earlier buffer if our
- // desiredPresent falls within +/- 1 second of the expected present.
- // Otherwise, bogus desiredPresent times (e.g., 0 or a small
- // relative timestamp), which normally mean "ignore the timestamp
- // and acquire immediately", would cause us to drop frames.
+ BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
+
+ // If expectedPresent is specified, we may not want to return a buffer yet.
+ // If it's specified and there's more than one buffer queued, we may want
+ // to drop a buffer.
+ if (expectedPresent != 0) {
+ const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
+
+ // The 'expectedPresent' argument indicates when the buffer is expected
+ // to be presented on-screen. If the buffer's desired present time is
+ // earlier (less) than expectedPresent -- meaning it will be displayed
+ // on time or possibly late if we show it as soon as possible -- we
+ // acquire and return it. If we don't want to display it until after the
+ // expectedPresent time, we return PRESENT_LATER without acquiring it.
//
- // We may want to add an additional criterion: don't drop the
- // earlier buffer if entry[1]'s fence hasn't signaled yet.
- const BufferItem& bufferItem(mCore->mQueue[1]);
- nsecs_t desiredPresent = bufferItem.mTimestamp;
- if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
- desiredPresent > expectedPresent) {
- // This buffer is set to display in the near future, or
- // desiredPresent is garbage. Either way we don't want to drop
- // the previous buffer just to get this on the screen sooner.
- BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
- PRId64 " (%" PRId64 ") now=%" PRId64,
- desiredPresent, expectedPresent,
- desiredPresent - expectedPresent,
- systemTime(CLOCK_MONOTONIC));
- break;
+ // To be safe, we don't defer acquisition if expectedPresent is more
+ // than one second in the future beyond the desired present time
+ // (i.e., we'd be holding the buffer for a long time).
+ //
+ // NOTE: Code assumes monotonic time values from the system clock
+ // are positive.
+
+ // Start by checking to see if we can drop frames. We skip this check if
+ // the timestamps are being auto-generated by Surface. If the app isn't
+ // generating timestamps explicitly, it probably doesn't want frames to
+ // be discarded based on them.
+ while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
+ const BufferItem& bufferItem(mCore->mQueue[1]);
+
+ // If dropping entry[0] would leave us with a buffer that the
+ // consumer is not yet ready for, don't drop it.
+ if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
+ break;
+ }
+
+ // If entry[1] is timely, drop entry[0] (and repeat). We apply an
+ // additional criterion here: we only drop the earlier buffer if our
+ // desiredPresent falls within +/- 1 second of the expected present.
+ // Otherwise, bogus desiredPresent times (e.g., 0 or a small
+ // relative timestamp), which normally mean "ignore the timestamp
+ // and acquire immediately", would cause us to drop frames.
+ //
+ // We may want to add an additional criterion: don't drop the
+ // earlier buffer if entry[1]'s fence hasn't signaled yet.
+ nsecs_t desiredPresent = bufferItem.mTimestamp;
+ if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
+ desiredPresent > expectedPresent) {
+ // This buffer is set to display in the near future, or
+ // desiredPresent is garbage. Either way we don't want to drop
+ // the previous buffer just to get this on the screen sooner.
+ BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
+ PRId64 " (%" PRId64 ") now=%" PRId64,
+ desiredPresent, expectedPresent,
+ desiredPresent - expectedPresent,
+ systemTime(CLOCK_MONOTONIC));
+ break;
+ }
+
+ BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
+ " size=%zu",
+ desiredPresent, expectedPresent, mCore->mQueue.size());
+ if (mCore->stillTracking(front)) {
+ // Front buffer is still in mSlots, so mark the slot as free
+ mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
+ mCore->mFreeBuffers.push_back(front->mSlot);
+ listener = mCore->mConnectedProducerListener;
+ ++numDroppedBuffers;
+ }
+ mCore->mQueue.erase(front);
+ front = mCore->mQueue.begin();
}
- BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
- " size=%zu",
- desiredPresent, expectedPresent, mCore->mQueue.size());
- if (mCore->stillTracking(front)) {
- // Front buffer is still in mSlots, so mark the slot as free
- mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
- mCore->mFreeBuffers.push_back(front->mSlot);
+ // See if the front buffer is ready to be acquired
+ nsecs_t desiredPresent = front->mTimestamp;
+ bool bufferIsDue = desiredPresent <= expectedPresent ||
+ desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
+ bool consumerIsReady = maxFrameNumber > 0 ?
+ front->mFrameNumber <= maxFrameNumber : true;
+ if (!bufferIsDue || !consumerIsReady) {
+ BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
+ " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64
+ " consumer=%" PRIu64,
+ desiredPresent, expectedPresent,
+ desiredPresent - expectedPresent,
+ systemTime(CLOCK_MONOTONIC),
+ front->mFrameNumber, maxFrameNumber);
+ return PRESENT_LATER;
}
- mCore->mQueue.erase(front);
- front = mCore->mQueue.begin();
- }
- // See if the front buffer is due
- nsecs_t desiredPresent = front->mTimestamp;
- if (desiredPresent > expectedPresent &&
- desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
- BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
- " (%" PRId64 ") now=%" PRId64,
- desiredPresent, expectedPresent,
+ BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
+ "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
desiredPresent - expectedPresent,
systemTime(CLOCK_MONOTONIC));
- return PRESENT_LATER;
}
- BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
- "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
- desiredPresent - expectedPresent,
- systemTime(CLOCK_MONOTONIC));
- }
+ int slot = front->mSlot;
+ *outBuffer = *front;
+ ATRACE_BUFFER_INDEX(slot);
- int slot = front->mSlot;
- *outBuffer = *front;
- ATRACE_BUFFER_INDEX(slot);
+ BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
+ slot, front->mFrameNumber, front->mGraphicBuffer->handle);
+ // If the front buffer is still being tracked, update its slot state
+ if (mCore->stillTracking(front)) {
+ mSlots[slot].mAcquireCalled = true;
+ mSlots[slot].mNeedsCleanupOnRelease = false;
+ mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
+ mSlots[slot].mFence = Fence::NO_FENCE;
+ }
- BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
- slot, front->mFrameNumber, front->mGraphicBuffer->handle);
- // If the front buffer is still being tracked, update its slot state
- if (mCore->stillTracking(front)) {
- mSlots[slot].mAcquireCalled = true;
- mSlots[slot].mNeedsCleanupOnRelease = false;
- mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
- mSlots[slot].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 (outBuffer->mAcquireCalled) {
+ outBuffer->mGraphicBuffer = NULL;
+ }
- // 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 (outBuffer->mAcquireCalled) {
- outBuffer->mGraphicBuffer = NULL;
- }
+ mCore->mQueue.erase(front);
- mCore->mQueue.erase(front);
+ // We might have freed a slot while dropping old buffers, or the producer
+ // may be blocked waiting for the number of buffers in the queue to
+ // decrease.
+ mCore->mDequeueCondition.broadcast();
- // We might have freed a slot while dropping old buffers, or the producer
- // may be blocked waiting for the number of buffers in the queue to
- // decrease.
- mCore->mDequeueCondition.broadcast();
+ ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
- ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+ mCore->validateConsistencyLocked();
+ }
- mCore->validateConsistencyLocked();
+ if (listener != NULL) {
+ for (int i = 0; i < numDroppedBuffers; ++i) {
+ listener->onBufferReleased();
+ }
+ }
return NO_ERROR;
}
@@ -236,6 +261,13 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot,
return INVALID_OPERATION;
}
+ if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
+ BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
+ "[queue %u]", buffer->getGenerationNumber(),
+ mCore->mGenerationNumber);
+ return BAD_VALUE;
+ }
+
// Find a free slot to put the buffer into
int found = BufferQueueCore::INVALID_BUFFER_SLOT;
if (!mCore->mFreeSlots.empty()) {
@@ -292,6 +324,8 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
releaseFence == NULL) {
+ BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
+ releaseFence.get());
return BAD_VALUE;
}
@@ -330,7 +364,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
mSlots[slot].mNeedsCleanupOnRelease = false;
return STALE_BUFFER_SLOT;
} else {
- BQ_LOGV("releaseBuffer: attempted to release buffer slot %d "
+ BQ_LOGE("releaseBuffer: attempted to release buffer slot %d "
"but its state was %d", slot, mSlots[slot].mBufferState);
return BAD_VALUE;
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index bc75ca7..851a396 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -70,7 +70,9 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
mTransformHint(0),
mIsAllocating(false),
mIsAllocatingCondition(),
- mAllowAllocation(true)
+ mAllowAllocation(true),
+ mBufferAge(0),
+ mGenerationNumber(0)
{
if (allocator == NULL) {
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -211,6 +213,7 @@ void BufferQueueCore::freeBufferLocked(int slot) {
}
mSlots[slot].mBufferState = BufferSlot::FREE;
mSlots[slot].mAcquireCalled = false;
+ mSlots[slot].mFrameNumber = 0;
// Destroy fence as BufferQueue now takes ownership
if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 86e45c8..87e5b4d 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -337,10 +337,19 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
+ mCore->mBufferAge = 0;
returnFlags |= BUFFER_NEEDS_REALLOCATION;
+ } else {
+ // We add 1 because that will be the frame number when this buffer
+ // is queued
+ mCore->mBufferAge =
+ mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
}
+ BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
+ mCore->mBufferAge);
+
if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
"slot=%d w=%d h=%d format=%u",
@@ -374,6 +383,7 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
return NO_INIT;
}
+ graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
} // Autolock scope
}
@@ -489,6 +499,13 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot,
Mutex::Autolock lock(mCore->mMutex);
mCore->waitWhileAllocatingLocked();
+ if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
+ BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
+ "[queue %u]", buffer->getGenerationNumber(),
+ mCore->mGenerationNumber);
+ return BAD_VALUE;
+ }
+
status_t returnFlags = NO_ERROR;
int found;
// TODO: Should we provide an async flag to attachBuffer? It seems
@@ -784,6 +801,13 @@ int BufferQueueProducer::query(int what, int *outValue) {
case NATIVE_WINDOW_DEFAULT_DATASPACE:
value = static_cast<int32_t>(mCore->mDefaultBufferDataSpace);
break;
+ case NATIVE_WINDOW_BUFFER_AGE:
+ if (mCore->mBufferAge > INT32_MAX) {
+ value = 0;
+ } else {
+ value = static_cast<int32_t>(mCore->mBufferAge);
+ }
+ break;
default:
return BAD_VALUE;
}
@@ -855,6 +879,7 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
mCore->mBufferHasBeenQueued = false;
mCore->mDequeueBufferCannotBlock =
mCore->mConsumerControlledByApp && producerControlledByApp;
+ mCore->mAllowAllocation = true;
return status;
}
@@ -897,8 +922,8 @@ status_t BufferQueueProducer::disconnect(int api) {
mCore->mSidebandStream.clear();
mCore->mDequeueCondition.broadcast();
listener = mCore->mConsumerListener;
- } else {
- BQ_LOGE("disconnect(P): connected to another API "
+ } else if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE("disconnect(P): still connected to another API "
"(cur=%d req=%d)", mCore->mConnectedApi, api);
status = BAD_VALUE;
}
@@ -1055,6 +1080,21 @@ status_t BufferQueueProducer::allowAllocation(bool allow) {
return NO_ERROR;
}
+status_t BufferQueueProducer::setGenerationNumber(uint32_t generationNumber) {
+ ATRACE_CALL();
+ BQ_LOGV("setGenerationNumber: %u", generationNumber);
+
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mGenerationNumber = generationNumber;
+ return NO_ERROR;
+}
+
+String8 BufferQueueProducer::getConsumerName() const {
+ ATRACE_CALL();
+ BQ_LOGV("getConsumerName: %s", mConsumerName.string());
+ return mConsumerName;
+}
+
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
// If we're here, it means that a producer we were connected to died.
// We're guaranteed that we are still connected to it because we remove
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index e576018..04ab06b 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -114,6 +114,21 @@ void ConsumerBase::onFrameAvailable(const BufferItem& item) {
}
}
+void ConsumerBase::onFrameReplaced(const BufferItem &item) {
+ CB_LOGV("onFrameReplaced");
+
+ sp<FrameAvailableListener> listener;
+ {
+ Mutex::Autolock lock(mMutex);
+ listener = mFrameAvailableListener.promote();
+ }
+
+ if (listener != NULL) {
+ CB_LOGV("actually calling onFrameReplaced");
+ listener->onFrameReplaced(item);
+ }
+}
+
void ConsumerBase::onBuffersReleased() {
Mutex::Autolock lock(mMutex);
@@ -156,6 +171,11 @@ void ConsumerBase::abandonLocked() {
mConsumer.clear();
}
+bool ConsumerBase::isAbandoned() {
+ Mutex::Autolock _l(mMutex);
+ return mAbandoned;
+}
+
void ConsumerBase::setFrameAvailableListener(
const wp<FrameAvailableListener>& listener) {
CB_LOGV("setFrameAvailableListener");
@@ -178,6 +198,22 @@ status_t ConsumerBase::detachBuffer(int slot) {
return result;
}
+status_t ConsumerBase::setDefaultBufferSize(uint32_t width, uint32_t height) {
+ Mutex::Autolock _l(mMutex);
+ return mConsumer->setDefaultBufferSize(width, height);
+}
+
+status_t ConsumerBase::setDefaultBufferFormat(PixelFormat defaultFormat) {
+ Mutex::Autolock _l(mMutex);
+ return mConsumer->setDefaultBufferFormat(defaultFormat);
+}
+
+status_t ConsumerBase::setDefaultBufferDataSpace(
+ android_dataspace defaultDataSpace) {
+ Mutex::Autolock _l(mMutex);
+ return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
+}
+
void ConsumerBase::dump(String8& result) const {
dump(result, "");
}
@@ -196,8 +232,8 @@ void ConsumerBase::dumpLocked(String8& result, const char* prefix) const {
}
status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
- nsecs_t presentWhen) {
- status_t err = mConsumer->acquireBuffer(item, presentWhen);
+ nsecs_t presentWhen, uint64_t maxFrameNumber) {
+ status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
if (err != NO_ERROR) {
return err;
}
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index eb39469..e29b740 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -56,25 +56,6 @@ void CpuConsumer::setName(const String8& name) {
mConsumer->setConsumerName(name);
}
-status_t CpuConsumer::setDefaultBufferSize(uint32_t width, uint32_t height)
-{
- Mutex::Autolock _l(mMutex);
- return mConsumer->setDefaultBufferSize(width, height);
-}
-
-status_t CpuConsumer::setDefaultBufferFormat(PixelFormat defaultFormat)
-{
- Mutex::Autolock _l(mMutex);
- return mConsumer->setDefaultBufferFormat(defaultFormat);
-}
-
-status_t CpuConsumer::setDefaultBufferDataSpace(
- android_dataspace defaultDataSpace)
-{
- Mutex::Autolock _l(mMutex);
- return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
-}
-
static bool isPossiblyYUV(PixelFormat format) {
switch (static_cast<int>(format)) {
case HAL_PIXEL_FORMAT_RGBA_8888:
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 96c0841..757e08a 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -344,8 +344,9 @@ sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() {
}
status_t GLConsumer::acquireBufferLocked(BufferItem *item,
- nsecs_t presentWhen) {
- status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen);
+ nsecs_t presentWhen, uint64_t maxFrameNumber) {
+ status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen,
+ maxFrameNumber);
if (err != NO_ERROR) {
return err;
}
@@ -900,14 +901,18 @@ Rect GLConsumer::getCurrentCrop() const {
// The crop is too wide
if (newWidth < currentWidth) {
- uint32_t dw = (currentWidth - newWidth) / 2;
- outCrop.left += dw;
- outCrop.right -= dw;
+ uint32_t dw = currentWidth - newWidth;
+ auto halfdw = dw / 2;
+ outCrop.left += halfdw;
+ // Not halfdw because it would subtract 1 too few when dw is odd
+ outCrop.right -= (dw - halfdw);
// The crop is too tall
} else if (newHeight < currentHeight) {
- uint32_t dh = (currentHeight - newHeight) / 2;
- outCrop.top += dh;
- outCrop.bottom -= dh;
+ uint32_t dh = currentHeight - newHeight;
+ auto halfdh = dh / 2;
+ outCrop.top += halfdh;
+ // Not halfdh because it would subtract 1 too few when dh is odd
+ outCrop.bottom -= (dh - halfdh);
}
GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index 09b63a1..3009989 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -59,6 +59,9 @@ public:
if (result == NO_ERROR) {
graphicBuffer = new GraphicBuffer();
result = reply.read(*graphicBuffer);
+ if (result != NO_ERROR) {
+ graphicBuffer.clear();
+ }
// reply.readStrongBinder();
// here we don't even have to read the BufferReference from
// the parcel, it'll die with the parcel.
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 3f23c2f..b86f4c5 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -66,10 +66,12 @@ public:
virtual ~BpGraphicBufferConsumer();
- virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) {
+ virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen,
+ uint64_t maxFrameNumber) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
data.writeInt64(presentWhen);
+ data.writeUint64(maxFrameNumber);
status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply);
if (result != NO_ERROR) {
return result;
@@ -295,7 +297,8 @@ status_t BnGraphicBufferConsumer::onTransact(
CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
BufferItem item;
int64_t presentWhen = data.readInt64();
- status_t result = acquireBuffer(&item, presentWhen);
+ uint64_t maxFrameNumber = data.readUint64();
+ status_t result = acquireBuffer(&item, presentWhen, maxFrameNumber);
status_t err = reply->write(item);
if (err) return err;
reply->writeInt32(result);
@@ -414,6 +417,15 @@ status_t BnGraphicBufferConsumer::onTransact(
reply->writeInt32(result);
return NO_ERROR;
}
+ case GET_SIDEBAND_STREAM: {
+ CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+ sp<NativeHandle> stream = getSidebandStream();
+ reply->writeInt32(static_cast<int32_t>(stream != NULL));
+ if (stream != NULL) {
+ reply->writeNativeHandle(stream->handle());
+ }
+ return NO_ERROR;
+ }
case DUMP: {
CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
String8 result = data.readString8();
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 74a40ee..8bdbc22 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -47,6 +47,8 @@ enum {
SET_SIDEBAND_STREAM,
ALLOCATE_BUFFERS,
ALLOW_ALLOCATION,
+ SET_GENERATION_NUMBER,
+ GET_CONSUMER_NAME,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -284,6 +286,28 @@ public:
result = reply.readInt32();
return result;
}
+
+ virtual status_t setGenerationNumber(uint32_t generationNumber) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeUint32(generationNumber);
+ status_t result = remote()->transact(SET_GENERATION_NUMBER, data, &reply);
+ if (result == NO_ERROR) {
+ result = reply.readInt32();
+ }
+ return result;
+ }
+
+ virtual String8 getConsumerName() const {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ status_t result = remote()->transact(GET_CONSUMER_NAME, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getConsumerName failed to transact: %d", result);
+ return String8("TransactFailed");
+ }
+ return reply.readString8();
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -448,6 +472,18 @@ status_t BnGraphicBufferProducer::onTransact(
reply->writeInt32(result);
return NO_ERROR;
}
+ case SET_GENERATION_NUMBER: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ uint32_t generationNumber = data.readUint32();
+ status_t result = setGenerationNumber(generationNumber);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
+ case GET_CONSUMER_NAME: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ reply->writeString8(getConsumerName());
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp
index 8e09e7c..f581b5c 100644
--- a/libs/gui/ISensorServer.cpp
+++ b/libs/gui/ISensorServer.cpp
@@ -35,6 +35,7 @@ namespace android {
enum {
GET_SENSOR_LIST = IBinder::FIRST_CALL_TRANSACTION,
CREATE_SENSOR_EVENT_CONNECTION,
+ ENABLE_DATA_INJECTION
};
class BpSensorServer : public BpInterface<ISensorServer>
@@ -47,10 +48,11 @@ public:
virtual ~BpSensorServer();
- virtual Vector<Sensor> getSensorList()
+ virtual Vector<Sensor> getSensorList(const String16& opPackageName)
{
Parcel data, reply;
data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+ data.writeString16(opPackageName);
remote()->transact(GET_SENSOR_LIST, data, &reply);
Sensor s;
Vector<Sensor> v;
@@ -63,13 +65,24 @@ public:
return v;
}
- virtual sp<ISensorEventConnection> createSensorEventConnection()
+ virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
+ int mode, const String16& opPackageName)
{
Parcel data, reply;
data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+ data.writeString8(packageName);
+ data.writeInt32(mode);
+ data.writeString16(opPackageName);
remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply);
return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
}
+
+ virtual int isDataInjectionEnabled() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+ remote()->transact(ENABLE_DATA_INJECTION, data, &reply);
+ return reply.readInt32();
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -86,7 +99,8 @@ status_t BnSensorServer::onTransact(
switch(code) {
case GET_SENSOR_LIST: {
CHECK_INTERFACE(ISensorServer, data, reply);
- Vector<Sensor> v(getSensorList());
+ const String16& opPackageName = data.readString16();
+ Vector<Sensor> v(getSensorList(opPackageName));
size_t n = v.size();
reply->writeUint32(static_cast<uint32_t>(n));
for (size_t i = 0; i < n; i++) {
@@ -96,10 +110,20 @@ status_t BnSensorServer::onTransact(
}
case CREATE_SENSOR_EVENT_CONNECTION: {
CHECK_INTERFACE(ISensorServer, data, reply);
- sp<ISensorEventConnection> connection(createSensorEventConnection());
+ String8 packageName = data.readString8();
+ int32_t mode = data.readInt32();
+ const String16& opPackageName = data.readString16();
+ sp<ISensorEventConnection> connection(createSensorEventConnection(packageName, mode,
+ opPackageName));
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
+ case ENABLE_DATA_INJECTION: {
+ CHECK_INTERFACE(ISensorServer, data, reply);
+ int32_t ret = isDataInjectionEnabled();
+ reply->writeInt32(static_cast<int32_t>(ret));
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 35661f2..4b3603e 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -25,6 +25,9 @@
#include <hardware/sensors.h>
+#include <binder/AppOpsManager.h>
+#include <binder/IServiceManager.h>
+
#include <gui/Sensor.h>
#include <log/log.h>
@@ -113,11 +116,13 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion)
mStringType = SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED;
mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
break;
- case SENSOR_TYPE_HEART_RATE:
+ case SENSOR_TYPE_HEART_RATE: {
mStringType = SENSOR_STRING_TYPE_HEART_RATE;
mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS;
+ AppOpsManager appOps;
+ mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
- break;
+ } break;
case SENSOR_TYPE_LIGHT:
mStringType = SENSOR_STRING_TYPE_LIGHT;
mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
@@ -218,6 +223,10 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion)
}
if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor->requiredPermission) {
mRequiredPermission = hwSensor->requiredPermission;
+ if (!strcmp(mRequiredPermission, SENSOR_PERMISSION_BODY_SENSORS)) {
+ AppOpsManager appOps;
+ mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
+ }
}
if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
@@ -252,6 +261,17 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion)
}
}
+
+ if (mRequiredPermission.length() > 0) {
+ // If the sensor is protected by a permission we need to know if it is
+ // a runtime one to determine whether we can use the permission cache.
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+ if (binder != 0) {
+ sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
+ mRequiredPermissionRuntime = permCtrl->isRuntimePermission(
+ String16(mRequiredPermission));
+ }
+ }
}
Sensor::~Sensor()
@@ -318,6 +338,14 @@ const String8& Sensor::getRequiredPermission() const {
return mRequiredPermission;
}
+bool Sensor::isRequiredPermissionRuntime() const {
+ return mRequiredPermissionRuntime;
+}
+
+int32_t Sensor::getRequiredAppOp() const {
+ return mRequiredAppOp;
+}
+
int32_t Sensor::getMaxDelay() const {
return mMaxDelay;
}
@@ -339,7 +367,8 @@ size_t Sensor::getFlattenedSize() const
size_t fixedSize =
sizeof(int32_t) * 3 +
sizeof(float) * 4 +
- sizeof(int32_t) * 5;
+ sizeof(int32_t) * 6 +
+ sizeof(bool);
size_t variableSize =
sizeof(uint32_t) + FlattenableUtils::align<4>(mName.length()) +
@@ -369,6 +398,8 @@ status_t Sensor::flatten(void* buffer, size_t size) const {
FlattenableUtils::write(buffer, size, mFifoMaxEventCount);
flattenString8(buffer, size, mStringType);
flattenString8(buffer, size, mRequiredPermission);
+ FlattenableUtils::write(buffer, size, mRequiredPermissionRuntime);
+ FlattenableUtils::write(buffer, size, mRequiredAppOp);
FlattenableUtils::write(buffer, size, mMaxDelay);
FlattenableUtils::write(buffer, size, mFlags);
return NO_ERROR;
@@ -407,6 +438,8 @@ status_t Sensor::unflatten(void const* buffer, size_t size) {
if (!unflattenString8(buffer, size, mRequiredPermission)) {
return NO_MEMORY;
}
+ FlattenableUtils::read(buffer, size, mRequiredPermissionRuntime);
+ FlattenableUtils::read(buffer, size, mRequiredAppOp);
FlattenableUtils::read(buffer, size, mMaxDelay);
FlattenableUtils::read(buffer, size, mFlags);
return NO_ERROR;
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 76ae470..4b7986e 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <linux/errno.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -149,6 +150,23 @@ status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const
return mSensorEventConnection->setEventRate(sensor->getHandle(), ns);
}
+status_t SensorEventQueue::injectSensorEvent(const ASensorEvent& event) {
+ do {
+ // Blocking call.
+ ssize_t size = ::send(mSensorChannel->getFd(), &event, sizeof(event), MSG_NOSIGNAL);
+ if (size >= 0) {
+ return NO_ERROR;
+ } else if (size < 0 && errno == EAGAIN) {
+ // If send is returning a "Try again" error, sleep for 100ms and try again. In all
+ // other cases log a failure and exit.
+ usleep(100000);
+ } else {
+ ALOGE("injectSensorEvent failure %s %zd", strerror(errno), size);
+ return INVALID_OPERATION;
+ }
+ } while (true);
+}
+
void SensorEventQueue::sendAck(const ASensorEvent* events, int count) {
for (int i = 0; i < count; ++i) {
if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) {
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
index d6df404..dd37781 100644
--- a/libs/gui/SensorManager.cpp
+++ b/libs/gui/SensorManager.cpp
@@ -36,10 +36,8 @@
namespace android {
// ----------------------------------------------------------------------------
-ANDROID_SINGLETON_STATIC_INSTANCE(SensorManager)
-
-SensorManager::SensorManager()
- : mSensorList(0)
+SensorManager::SensorManager(const String16& opPackageName)
+ : mSensorList(0), mOpPackageName(opPackageName)
{
// okay we're not locked here, but it's not needed during construction
assertStateLocked();
@@ -88,7 +86,7 @@ status_t SensorManager::assertStateLocked() const {
mDeathObserver = new DeathObserver(*const_cast<SensorManager *>(this));
IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver);
- mSensors = mSensorServer->getSensorList();
+ mSensors = mSensorServer->getSensorList(mOpPackageName);
size_t count = mSensors.size();
mSensorList =
static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
@@ -100,8 +98,6 @@ status_t SensorManager::assertStateLocked() const {
return NO_ERROR;
}
-
-
ssize_t SensorManager::getSensorList(Sensor const* const** list) const
{
Mutex::Autolock _l(mLock);
@@ -139,18 +135,17 @@ Sensor const* SensorManager::getDefaultSensor(int type)
return NULL;
}
-sp<SensorEventQueue> SensorManager::createEventQueue()
-{
+sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) {
sp<SensorEventQueue> queue;
Mutex::Autolock _l(mLock);
while (assertStateLocked() == NO_ERROR) {
sp<ISensorEventConnection> connection =
- mSensorServer->createSensorEventConnection();
+ mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName);
if (connection == NULL) {
- // SensorService just died.
- ALOGE("createEventQueue: connection is NULL. SensorService died.");
- continue;
+ // SensorService just died or the app doesn't have required permissions.
+ ALOGE("createEventQueue: connection is NULL.");
+ return NULL;
}
queue = new SensorEventQueue(connection);
break;
@@ -158,5 +153,13 @@ sp<SensorEventQueue> SensorManager::createEventQueue()
return queue;
}
+bool SensorManager::isDataInjectionEnabled() {
+ Mutex::Autolock _l(mLock);
+ if (assertStateLocked() == NO_ERROR) {
+ return mSensorServer->isDataInjectionEnabled();
+ }
+ return false;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index b8acad2..4b76f98 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -42,7 +42,8 @@ namespace android {
Surface::Surface(
const sp<IGraphicBufferProducer>& bufferProducer,
bool controlledByApp)
- : mGraphicBufferProducer(bufferProducer)
+ : mGraphicBufferProducer(bufferProducer),
+ mGenerationNumber(0)
{
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
@@ -102,6 +103,18 @@ void Surface::allocateBuffers() {
reqHeight, mReqFormat, mReqUsage);
}
+status_t Surface::setGenerationNumber(uint32_t generation) {
+ status_t result = mGraphicBufferProducer->setGenerationNumber(generation);
+ if (result == NO_ERROR) {
+ mGenerationNumber = generation;
+ }
+ return result;
+}
+
+String8 Surface::getConsumerName() const {
+ return mGraphicBufferProducer->getConsumerName();
+}
+
int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
Surface* c = getSelf(window);
return c->setSwapInterval(interval);
@@ -267,6 +280,9 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer,
Mutex::Autolock lock(mMutex);
int i = getSlotFromBufferLocked(buffer);
if (i < 0) {
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
return i;
}
sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
@@ -308,6 +324,9 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
}
int i = getSlotFromBufferLocked(buffer);
if (i < 0) {
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
return i;
}
@@ -325,16 +344,61 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) {
input.setSurfaceDamage(Region::INVALID_REGION);
} else {
- // The surface damage was specified using the OpenGL ES convention of
- // the origin being in the bottom-left corner. Here we flip to the
- // convention that the rest of the system uses (top-left corner) by
- // subtracting all top/bottom coordinates from the buffer height.
+ // Here we do two things:
+ // 1) The surface damage was specified using the OpenGL ES convention of
+ // the origin being in the bottom-left corner. Here we flip to the
+ // convention that the rest of the system uses (top-left corner) by
+ // subtracting all top/bottom coordinates from the buffer height.
+ // 2) If the buffer is coming in rotated (for example, because the EGL
+ // implementation is reacting to the transform hint coming back from
+ // SurfaceFlinger), the surface damage needs to be rotated the
+ // opposite direction, since it was generated assuming an unrotated
+ // buffer (the app doesn't know that the EGL implementation is
+ // reacting to the transform hint behind its back). The
+ // transformations in the switch statement below apply those
+ // complementary rotations (e.g., if 90 degrees, rotate 270 degrees).
+
+ int width = buffer->width;
+ int height = buffer->height;
+ bool rotated90 = (mTransform ^ mStickyTransform) &
+ NATIVE_WINDOW_TRANSFORM_ROT_90;
+ if (rotated90) {
+ std::swap(width, height);
+ }
+
Region flippedRegion;
for (auto rect : mDirtyRegion) {
- auto top = buffer->height - rect.bottom;
- auto bottom = buffer->height - rect.top;
- Rect flippedRect{rect.left, top, rect.right, bottom};
- flippedRegion.orSelf(flippedRect);
+ int left = rect.left;
+ int right = rect.right;
+ int top = height - rect.bottom; // Flip from OpenGL convention
+ int bottom = height - rect.top; // Flip from OpenGL convention
+ switch (mTransform ^ mStickyTransform) {
+ case NATIVE_WINDOW_TRANSFORM_ROT_90: {
+ // Rotate 270 degrees
+ Rect flippedRect{top, width - right, bottom, width - left};
+ flippedRegion.orSelf(flippedRect);
+ break;
+ }
+ case NATIVE_WINDOW_TRANSFORM_ROT_180: {
+ // Rotate 180 degrees
+ Rect flippedRect{width - right, height - bottom,
+ width - left, height - top};
+ flippedRegion.orSelf(flippedRect);
+ break;
+ }
+ case NATIVE_WINDOW_TRANSFORM_ROT_270: {
+ // Rotate 90 degrees
+ Rect flippedRect{height - bottom, left,
+ height - top, right};
+ flippedRegion.orSelf(flippedRect);
+ break;
+ }
+ default: {
+ Rect flippedRect{left, top, right, bottom};
+ flippedRegion.orSelf(flippedRect);
+ break;
+ }
+ }
}
input.setSurfaceDamage(flippedRegion);
@@ -651,7 +715,7 @@ int Surface::disconnect(int api) {
return err;
}
-int Surface::detachNextBuffer(ANativeWindowBuffer** outBuffer,
+int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence) {
ATRACE_CALL();
ALOGV("Surface::detachNextBuffer");
@@ -670,7 +734,7 @@ int Surface::detachNextBuffer(ANativeWindowBuffer** outBuffer,
return result;
}
- *outBuffer = buffer.get();
+ *outBuffer = buffer;
if (fence != NULL && fence->isValid()) {
*outFence = fence;
} else {
@@ -688,11 +752,14 @@ int Surface::attachBuffer(ANativeWindowBuffer* buffer)
Mutex::Autolock lock(mMutex);
sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer));
+ uint32_t priorGeneration = graphicBuffer->mGenerationNumber;
+ graphicBuffer->mGenerationNumber = mGenerationNumber;
int32_t attachedSlot = -1;
status_t result = mGraphicBufferProducer->attachBuffer(
&attachedSlot, graphicBuffer);
if (result != NO_ERROR) {
ALOGE("attachBuffer: IGraphicBufferProducer call failed (%d)", result);
+ graphicBuffer->mGenerationNumber = priorGeneration;
return result;
}
mSlots[attachedSlot].buffer = graphicBuffer;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 707a321..6ad47d8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -310,11 +310,10 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
return BAD_INDEX;
- if (mask & layer_state_t::eLayerOpaque) {
- s->what |= layer_state_t::eOpacityChanged;
- }
- if (mask & layer_state_t::eLayerHidden) {
- s->what |= layer_state_t::eVisibilityChanged;
+ if (mask & layer_state_t::eLayerOpaque ||
+ mask & layer_state_t::eLayerHidden ||
+ mask & layer_state_t::eLayerSecure) {
+ s->what |= layer_state_t::eFlagsChanged;
}
s->flags &= ~mask;
s->flags |= (flags & mask);
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 1584fef..1a54875 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "BufferQueue_test"
//#define LOG_NDEBUG 0
+#include "DummyConsumer.h"
+
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
#include <gui/IProducerListener.h>
@@ -67,12 +69,6 @@ protected:
sp<IGraphicBufferConsumer> mConsumer;
};
-struct DummyConsumer : public BnConsumerListener {
- virtual void onFrameAvailable(const BufferItem& /* item */) {}
- virtual void onBuffersReleased() {}
- virtual void onSidebandStreamChanged() {}
-};
-
static const uint32_t TEST_DATA = 0x12345678u;
// XXX: Tests that fork a process to hold the BufferQueue must run before tests
@@ -402,4 +398,46 @@ TEST_F(BufferQueueTest, TestDisallowingAllocation) {
WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN));
}
+TEST_F(BufferQueueTest, TestGenerationNumbers) {
+ createBufferQueue();
+ sp<DummyConsumer> dc(new DummyConsumer);
+ ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+ NATIVE_WINDOW_API_CPU, true, &output));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(1));
+
+ // Get one buffer to play with
+ int slot;
+ sp<Fence> fence;
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+ mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, 0));
+
+ sp<GraphicBuffer> buffer;
+ ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+
+ // Ensure that the generation number we set propagates to allocated buffers
+ ASSERT_EQ(1U, buffer->getGenerationNumber());
+
+ ASSERT_EQ(OK, mProducer->detachBuffer(slot));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(2));
+
+ // These should fail, since we've changed the generation number on the queue
+ int outSlot;
+ ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&outSlot, buffer));
+ ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&outSlot, buffer));
+
+ buffer->setGenerationNumber(2);
+
+ // This should succeed now that we've changed the buffer's generation number
+ ASSERT_EQ(OK, mProducer->attachBuffer(&outSlot, buffer));
+
+ ASSERT_EQ(OK, mProducer->detachBuffer(outSlot));
+
+ // This should also succeed with the new generation number
+ ASSERT_EQ(OK, mConsumer->attachBuffer(&outSlot, buffer));
+}
+
} // namespace android
diff --git a/libs/gui/tests/DummyConsumer.h b/libs/gui/tests/DummyConsumer.h
new file mode 100644
index 0000000..0511e16
--- /dev/null
+++ b/libs/gui/tests/DummyConsumer.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/IConsumerListener.h>
+
+namespace android {
+
+struct DummyConsumer : public BnConsumerListener {
+ virtual void onFrameAvailable(const BufferItem& /* item */) {}
+ virtual void onBuffersReleased() {}
+ virtual void onSidebandStreamChanged() {}
+};
+
+} // namespace android
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index ff58420..4ef9a69 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -299,7 +299,7 @@ TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) {
ASSERT_NO_FATAL_FAILURE(ConnectProducer());
// One past the end of the last 'query' enum value. Update this if we add more enums.
- const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_DEFAULT_DATASPACE + 1;
+ const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1;
int value;
// What was out of range
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index d750cd0..1a50b24 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -27,6 +27,9 @@
#include <utils/Log.h>
#include <utils/Thread.h>
+EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+#define CROP_EXT_STR "EGL_ANDROID_image_crop"
+
namespace android {
class SurfaceTextureClientTest : public ::testing::Test {
@@ -615,6 +618,18 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers)
}
TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
+ // Query to see if the image crop extension exists
+ EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
+ size_t cropExtLen = strlen(CROP_EXT_STR);
+ size_t extsLen = strlen(exts);
+ bool equal = !strcmp(CROP_EXT_STR, exts);
+ bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
+ bool atEnd = (cropExtLen+1) < extsLen &&
+ !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
+ bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
+ bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle;
+
android_native_buffer_t* buf[3];
float mtx[16] = {};
android_native_rect_t crop;
@@ -633,15 +648,17 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
mST->getTransformMatrix(mtx);
- // This accounts for the .5 texel shrink for each edge that's included in the
- // transform matrix to avoid texturing outside the crop region.
- EXPECT_EQ(0.5, mtx[0]);
+ // If the egl image crop extension is not present, this accounts for the
+ // .5 texel shrink for each edge that's included in the transform matrix
+ // to avoid texturing outside the crop region. Otherwise the crop is not
+ // included in the transform matrix.
+ EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]);
EXPECT_EQ(0.f, mtx[1]);
EXPECT_EQ(0.f, mtx[2]);
EXPECT_EQ(0.f, mtx[3]);
EXPECT_EQ(0.f, mtx[4]);
- EXPECT_EQ(-0.5, mtx[5]);
+ EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]);
EXPECT_EQ(0.f, mtx[6]);
EXPECT_EQ(0.f, mtx[7]);
@@ -650,8 +667,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi
EXPECT_EQ(1.f, mtx[10]);
EXPECT_EQ(0.f, mtx[11]);
- EXPECT_EQ(0.0625f, mtx[12]);
- EXPECT_EQ(0.5625f, mtx[13]);
+ EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]);
+ EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]);
EXPECT_EQ(0.f, mtx[14]);
EXPECT_EQ(1.f, mtx[15]);
}
diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
index f4c7961..6edbfb8 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
@@ -188,10 +188,10 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
// This test should have the only reference to buffer 0.
EXPECT_EQ(1, buffers[0]->getStrongCount());
- // The GLConsumer should hold a single reference to buffer 1 in its
- // mCurrentBuffer member. All of the references in the slots should have
- // been released.
- EXPECT_EQ(2, buffers[1]->getStrongCount());
+ // The GLConsumer should hold one reference to buffer 1 in its
+ // mCurrentTextureImage member and another reference in mEglSlots. The third
+ // reference is in this test.
+ EXPECT_EQ(3, buffers[1]->getStrongCount());
}
TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
@@ -235,14 +235,19 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
ASSERT_EQ(EGL_SUCCESS, eglGetError());
mProducerEglSurface = EGL_NO_SURFACE;
- EXPECT_EQ(1, buffers[0]->getStrongCount());
EXPECT_EQ(1, buffers[1]->getStrongCount());
// Depending on how lazily the GL driver dequeues buffers, we may end up
- // with either two or three total buffers. If there are three, make sure
- // the last one was properly down-ref'd.
+ // with either two or three total buffers. If there are three, each entry
+ // of the buffers array will be unique and there should only be one
+ // reference (the one in this test). If there are two the first and last
+ // element in the array will be equal meaning that buffer representing both
+ // 0 and 2 will have two references (one for 0 and one for 2).
if (buffers[2] != buffers[0]) {
+ EXPECT_EQ(1, buffers[0]->getStrongCount());
EXPECT_EQ(1, buffers[2]->getStrongCount());
+ } else {
+ EXPECT_EQ(2, buffers[0]->getStrongCount());
}
}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 4f87824..3f495f8 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "DummyConsumer.h"
+
#include <gtest/gtest.h>
#include <binder/IMemory.h>
@@ -177,4 +179,53 @@ TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) {
ASSERT_EQ(TEST_DATASPACE, dataSpace);
}
+TEST_F(SurfaceTest, SettingGenerationNumber) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+
+ // Allocate a buffer with a generation number of 0
+ ANativeWindowBuffer* buffer;
+ int fenceFd;
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd));
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fenceFd));
+
+ // Detach the buffer and check its generation number
+ sp<GraphicBuffer> graphicBuffer;
+ sp<Fence> fence;
+ ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&graphicBuffer, &fence));
+ ASSERT_EQ(0U, graphicBuffer->getGenerationNumber());
+
+ ASSERT_EQ(NO_ERROR, surface->setGenerationNumber(1));
+ buffer = static_cast<ANativeWindowBuffer*>(graphicBuffer.get());
+
+ // This should change the generation number of the GraphicBuffer
+ ASSERT_EQ(NO_ERROR, surface->attachBuffer(buffer));
+
+ // Check that the new generation number sticks with the buffer
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, -1));
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd));
+ graphicBuffer = static_cast<GraphicBuffer*>(buffer);
+ ASSERT_EQ(1U, graphicBuffer->getGenerationNumber());
+}
+
+TEST_F(SurfaceTest, GetConsumerName) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+ consumer->consumerConnect(dummyConsumer, false);
+ consumer->setConsumerName(String8("TestConsumer"));
+
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+ native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+ EXPECT_STREQ("TestConsumer", surface->getConsumerName().string());
+}
+
}