Merge "atrace: Add f2fs sync and ext4 write tracepoints."
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index 8f4da65..671d031 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -1022,7 +1022,13 @@
// Make the profile directory write-only for group and other. Owner can rwx it.
if (chmod(profile_dir, 0711) < 0) {
ALOGE("cannot chown profile dir '%s': %s\n", profile_dir, strerror(errno));
- unlink(profile_dir);
+ rmdir(profile_dir);
+ return -1;
+ }
+
+ if (selinux_android_restorecon(profile_dir, 0) < 0) {
+ ALOGE("cannot restorecon profile dir '%s': %s\n", profile_dir, strerror(errno));
+ rmdir(profile_dir);
return -1;
}
}
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 129ea3e..b4e7ebe 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -281,6 +281,28 @@
*/
int ASensor_getMinDelay(ASensor const* sensor);
+/*
+ * Returns the maximum size of batches for this sensor. Batches will often be
+ * smaller, as the hardware fifo might be used for other sensors.
+ */
+int ASensor_getFifoMaxEventCount(ASensor const* sensor);
+
+/*
+ * Returns the hardware batch fifo size reserved to this sensor.
+ */
+int ASensor_getFifoReservedEventCount(ASensor const* sensor);
+
+/*
+ * Returns this sensor's string type.
+ */
+const char* ASensor_getStringType(ASensor const* sensor);
+
+/*
+ * Returns the permission required to see or access this sensor, or the
+ * empty string if none is required.
+ */
+const char* ASensor_getRequiredPermission(ASensor const* sensor);
+
#ifdef __cplusplus
};
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index f74dc26..da876ec 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -112,10 +112,6 @@
// needed gralloc buffers.
BufferQueue(const sp<IGraphicBufferAlloc>& allocator = NULL);
- static void createBufferQueue(sp<BnGraphicBufferProducer>* outProducer,
- sp<BnGraphicBufferConsumer>* outConsumer,
- const sp<IGraphicBufferAlloc>& allocator = NULL);
-
static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
const sp<IGraphicBufferAlloc>& allocator = NULL);
@@ -232,16 +228,8 @@
// will usually be the one obtained from dequeueBuffer.
virtual void cancelBuffer(int buf, const sp<Fence>& fence);
- // connect attempts to connect a producer API to the BufferQueue. This
- // must be called before any other IGraphicBufferProducer methods are
- // called except for getAllocator. A consumer must already be connected.
- //
- // This method will fail if connect was previously called on the
- // BufferQueue and no corresponding disconnect call was made (i.e. if
- // it's still connected to a producer).
- //
- // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
- virtual status_t connect(const sp<IBinder>& token,
+ // See IGraphicBufferProducer::connect
+ virtual status_t connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput* output);
// disconnect attempts to disconnect a producer API from the BufferQueue.
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 89f2779..cfcb7a5 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -46,9 +46,9 @@
namespace android {
class BufferItem;
-class IBinder;
class IConsumerListener;
class IGraphicBufferAlloc;
+class IProducerListener;
class BufferQueueCore : public virtual RefBase {
@@ -162,7 +162,7 @@
// mConnectedProducerToken is used to set a binder death notification on
// the producer.
- sp<IBinder> mConnectedProducerToken;
+ sp<IProducerListener> mConnectedProducerListener;
// mSlots is an array of buffer slots that must be mirrored on the producer
// side. This allows buffer ownership to be transferred between the producer
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 0013b0a..04692a5 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -140,7 +140,7 @@
// it's still connected to a producer).
//
// APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
- virtual status_t connect(const sp<IBinder>& token,
+ virtual status_t connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput* output);
// disconnect attempts to disconnect a producer API from the BufferQueue.
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 0874f03..2b61ab3 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -32,6 +32,7 @@
namespace android {
// ----------------------------------------------------------------------------
+class IProducerListener;
class NativeHandle;
class Surface;
@@ -344,9 +345,11 @@
// This method will fail if the connect was previously called on the
// IGraphicBufferProducer and no corresponding disconnect call was made.
//
- // The token needs to be any opaque binder object that lives in the
- // producer process -- it is solely used for obtaining a death notification
- // when the producer is killed.
+ // The listener is an optional binder callback object that can be used if
+ // the producer wants to be notified when the consumer releases a buffer
+ // back to the BufferQueue. It is also used to detect the death of the
+ // producer. If only the latter functionality is desired, there is a
+ // DummyProducerListener class in IProducerListener.h that can be used.
//
// The api should be one of the NATIVE_WINDOW_API_* values in <window.h>
//
@@ -370,7 +373,7 @@
//
// Additional negative errors may be returned by the internals, they
// should be treated as opaque fatal unrecoverable errors.
- virtual status_t connect(const sp<IBinder>& token,
+ virtual status_t connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput* output) = 0;
// disconnect attempts to disconnect a client API from the
diff --git a/include/gui/IProducerListener.h b/include/gui/IProducerListener.h
new file mode 100644
index 0000000..3848a6c
--- /dev/null
+++ b/include/gui/IProducerListener.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_IPRODUCERLISTENER_H
+#define ANDROID_GUI_IPRODUCERLISTENER_H
+
+#include <binder/IInterface.h>
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+// ProducerListener is the interface through which the BufferQueue notifies the
+// producer of events that the producer may wish to react to. Because the
+// producer will generally have a mutex that is locked during calls from the
+// producer to the BufferQueue, these calls from the BufferQueue to the
+// producer *MUST* be called only when the BufferQueue mutex is NOT locked.
+
+class ProducerListener : public virtual RefBase
+{
+public:
+ ProducerListener() {}
+ virtual ~ProducerListener() {}
+
+ // onBufferReleased is called from IGraphicBufferConsumer::releaseBuffer to
+ // notify the producer that a new buffer is free and ready to be dequeued.
+ //
+ // This is called without any lock held and can be called concurrently by
+ // multiple threads.
+ virtual void onBufferReleased() = 0; // Asynchronous
+};
+
+class IProducerListener : public ProducerListener, public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(ProducerListener)
+};
+
+class BnProducerListener : public BnInterface<IProducerListener>
+{
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags = 0);
+};
+
+class DummyProducerListener : public BnProducerListener
+{
+public:
+ virtual void onBufferReleased() {}
+};
+
+} // namespace android
+
+#endif
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 35dcd4e..efde5db 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -22,9 +22,12 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
#include <binder/IInterface.h>
+#include <ui/FrameStats.h>
#include <ui/PixelFormat.h>
#include <gui/IGraphicBufferAlloc.h>
@@ -122,6 +125,19 @@
uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform) = 0;
+
+
+ /* Clears the frame statistics for animations.
+ *
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t clearAnimationFrameStats() = 0;
+
+ /* Gets the frame statistics for animations.
+ *
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
};
// ----------------------------------------------------------------------------
@@ -145,6 +161,8 @@
GET_DISPLAY_INFO,
CONNECT_DISPLAY,
CAPTURE_SCREEN,
+ CLEAR_ANIMATION_FRAME_STATS,
+ GET_ANIMATION_FRAME_STATS
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index cb9816f..58c1f6a 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -25,6 +25,7 @@
#include <binder/IInterface.h>
+#include <ui/FrameStats.h>
#include <ui/PixelFormat.h>
namespace android {
@@ -65,6 +66,16 @@
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t destroySurface(const sp<IBinder>& handle) = 0;
+
+ /*
+ * Requires ACCESS_SURFACE_FLINGER permission
+ */
+ virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const = 0;
+
+ /*
+ * Requires ACCESS_SURFACE_FLINGER permission
+ */
+ virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index 0c81426..033b262 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -69,6 +69,8 @@
int32_t getVersion() const;
int32_t getFifoReservedEventCount() const;
int32_t getFifoMaxEventCount() const;
+ const String8& getStringType() const;
+ const String8& getRequiredPermission() const;
// LightFlattenable protocol
inline bool isFixedSize() const { return false; }
@@ -89,6 +91,10 @@
int32_t mVersion;
int32_t mFifoReservedEventCount;
int32_t mFifoMaxEventCount;
+ String8 mStringType;
+ String8 mRequiredPermission;
+ static void flattenString8(void*& buffer, size_t& size, const String8& string8);
+ static bool unflattenString8(void const*& buffer, size_t& size, String8& outputString8);
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index ac53f02..6a53ccb 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -28,6 +28,7 @@
#include <utils/SortedVector.h>
#include <utils/threads.h>
+#include <ui/FrameStats.h>
#include <ui/PixelFormat.h>
#include <gui/CpuConsumer.h>
@@ -125,6 +126,12 @@
status_t setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
status_t destroySurface(const sp<IBinder>& id);
+ status_t clearLayerFrameStats(const sp<IBinder>& token) const;
+ status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
+
+ static status_t clearAnimationFrameStats();
+ static status_t getAnimationFrameStats(FrameStats* outStats);
+
static void setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
static void setDisplayLayerStack(const sp<IBinder>& token,
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index f27754c..84fb9f9 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -24,6 +24,7 @@
#include <utils/RefBase.h>
#include <utils/threads.h>
+#include <ui/FrameStats.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
@@ -52,10 +53,10 @@
static bool isSameSurface(
const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
-
+
// release surface data from java
void clear();
-
+
status_t setLayerStack(int32_t layerStack);
status_t setLayer(int32_t layer);
status_t setPosition(float x, float y);
@@ -73,6 +74,9 @@
sp<Surface> getSurface() const;
+ status_t clearLayerFrameStats() const;
+ status_t getLayerFrameStats(FrameStats* outStats) const;
+
private:
// can't be copied
SurfaceControl& operator = (SurfaceControl& rhs);
@@ -90,7 +94,7 @@
status_t validate() const;
void destroy();
-
+
sp<SurfaceComposerClient> mClient;
sp<IBinder> mHandle;
sp<IGraphicBufferProducer> mGraphicBufferProducer;
diff --git a/include/input/Input.h b/include/input/Input.h
index bb5ceaf..077a03b 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -178,13 +178,9 @@
/* These flags are set by the input reader policy as it intercepts each event. */
- // Indicates that the screen was off when the event was received and the event
- // should wake the device.
- POLICY_FLAG_WOKE_HERE = 0x10000000,
-
- // Indicates that the screen was dim when the event was received and the event
- // should brighten the device.
- POLICY_FLAG_BRIGHT_HERE = 0x20000000,
+ // Indicates that the device was in an interactive state when the
+ // event was intercepted.
+ POLICY_FLAG_INTERACTIVE = 0x20000000,
// Indicates that the event should be dispatched to applications.
// The input event should still be sent to the InputDispatcher so that it can see all
diff --git a/include/ui/FrameStats.h b/include/ui/FrameStats.h
new file mode 100644
index 0000000..5fdf94d
--- /dev/null
+++ b/include/ui/FrameStats.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_FRAME_STATS_H
+#define ANDROID_UI_FRAME_STATS_H
+
+#include <utils/Flattenable.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class FrameStats : public LightFlattenable<FrameStats> {
+public:
+
+ /*
+ * Approximate refresh time, in nanoseconds.
+ */
+ nsecs_t refreshPeriodNano;
+
+ /*
+ * The times in nanoseconds for when the frame contents were posted by the producer (e.g.
+ * the application). They are either explicitly set or defaulted to the time when
+ * Surface::queueBuffer() was called.
+ */
+ Vector<nsecs_t> desiredPresentTimesNano;
+
+ /*
+ * The times in milliseconds for when the frame contents were presented on the screen.
+ */
+ Vector<nsecs_t> actualPresentTimesNano;
+
+ /*
+ * The times in nanoseconds for when the frame contents were ready to be presented. Note that
+ * a frame can be posted and still it contents being rendered asynchronously in GL. In such a
+ * case these are the times when the frame contents were completely rendered (i.e. their fences
+ * signaled).
+ */
+ Vector<nsecs_t> frameReadyTimesNano;
+
+ // LightFlattenable
+ bool isFixedSize() const;
+ size_t getFlattenedSize() const;
+ status_t flatten(void* buffer, size_t size) const;
+ status_t unflatten(void const* buffer, size_t size);
+};
+
+}; // namespace android
+
+#endif // ANDROID_UI_FRAME_STATS_H
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 3cf628c..a92424c 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -88,7 +88,8 @@
uint32_t getUsage() const { return usage; }
PixelFormat getPixelFormat() const { return format; }
Rect getBounds() const { return Rect(width, height); }
-
+ uint64_t getId() const { return mId; }
+
status_t reallocate(uint32_t w, uint32_t h, PixelFormat f, uint32_t usage);
status_t lock(uint32_t usage, void** vaddr);
@@ -146,6 +147,8 @@
// If we're wrapping another buffer then this reference will make sure it
// doesn't get freed.
sp<ANativeWindowBuffer> mWrappedBuffer;
+
+ uint64_t mId;
};
}; // namespace android
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 0a77317..04a8a8d 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -21,6 +21,7 @@
IDisplayEventConnection.cpp \
IGraphicBufferAlloc.cpp \
IGraphicBufferProducer.cpp \
+ IProducerListener.cpp \
ISensorEventConnection.cpp \
ISensorServer.cpp \
ISurfaceComposer.cpp \
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index c306f9d..d04b67d 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -43,19 +43,6 @@
}
}
-void BufferQueue::createBufferQueue(sp<BnGraphicBufferProducer>* outProducer,
- sp<BnGraphicBufferConsumer>* outConsumer,
- const sp<IGraphicBufferAlloc>& allocator) {
- LOG_ALWAYS_FATAL_IF(outProducer == NULL,
- "BufferQueue: outProducer must not be NULL");
- LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
- "BufferQueue: outConsumer must not be NULL");
-
- sp<BufferQueueCore> core(new BufferQueueCore(allocator));
- *outProducer = new BufferQueueProducer(core);
- *outConsumer = new BufferQueueConsumer(core);
-}
-
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
const sp<IGraphicBufferAlloc>& allocator) {
@@ -65,8 +52,19 @@
"BufferQueue: outConsumer must not be NULL");
sp<BufferQueueCore> core(new BufferQueueCore(allocator));
- *outProducer = new BufferQueueProducer(core);
- *outConsumer = new BufferQueueConsumer(core);
+ LOG_ALWAYS_FATAL_IF(core == NULL,
+ "BufferQueue: failed to create BufferQueueCore");
+
+ sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
+ LOG_ALWAYS_FATAL_IF(producer == NULL,
+ "BufferQueue: failed to create BufferQueueProducer");
+
+ sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
+ LOG_ALWAYS_FATAL_IF(consumer == NULL,
+ "BufferQueue: failed to create BufferQueueConsumer");
+
+ *outProducer = producer;
+ *outConsumer = consumer;
}
BufferQueue::BufferQueue(const sp<IGraphicBufferAlloc>& allocator) :
@@ -119,9 +117,9 @@
mProducer->cancelBuffer(buf, fence);
}
-status_t BufferQueue::connect(const sp<IBinder>& token,
+status_t BufferQueue::connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput* output) {
- return mProducer->connect(token, api, producerControlledByApp, output);
+ return mProducer->connect(listener, api, producerControlledByApp, output);
}
status_t BufferQueue::disconnect(int api) {
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 756cd61..995ed5e 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -22,6 +22,7 @@
#include <gui/BufferQueueConsumer.h>
#include <gui/BufferQueueCore.h>
#include <gui/IConsumerListener.h>
+#include <gui/IProducerListener.h>
namespace android {
@@ -261,42 +262,52 @@
return BAD_VALUE;
}
- Mutex::Autolock lock(mCore->mMutex);
+ sp<IProducerListener> listener;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
- // If the frame number has changed because the buffer has been reallocated,
- // we can ignore this releaseBuffer for the old buffer
- if (frameNumber != mSlots[slot].mFrameNumber) {
- return STALE_BUFFER_SLOT;
- }
+ // If the frame number has changed because the buffer has been reallocated,
+ // we can ignore this releaseBuffer for the old buffer
+ if (frameNumber != mSlots[slot].mFrameNumber) {
+ return STALE_BUFFER_SLOT;
+ }
- // Make sure this buffer hasn't been queued while acquired by the consumer
- BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin());
- while (current != mCore->mQueue.end()) {
- if (current->mSlot == slot) {
- BQ_LOGE("releaseBuffer: buffer slot %d pending release is "
- "currently queued", slot);
+ // Make sure this buffer hasn't been queued while acquired by the consumer
+ BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin());
+ while (current != mCore->mQueue.end()) {
+ if (current->mSlot == slot) {
+ BQ_LOGE("releaseBuffer: buffer slot %d pending release is "
+ "currently queued", slot);
+ return BAD_VALUE;
+ }
+ ++current;
+ }
+
+ if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
+ mSlots[slot].mEglDisplay = eglDisplay;
+ mSlots[slot].mEglFence = eglFence;
+ mSlots[slot].mFence = releaseFence;
+ mSlots[slot].mBufferState = BufferSlot::FREE;
+ listener = mCore->mConnectedProducerListener;
+ BQ_LOGV("releaseBuffer: releasing slot %d", slot);
+ } else if (mSlots[slot].mNeedsCleanupOnRelease) {
+ BQ_LOGV("releaseBuffer: releasing a stale buffer slot %d "
+ "(state = %d)", slot, mSlots[slot].mBufferState);
+ mSlots[slot].mNeedsCleanupOnRelease = false;
+ return STALE_BUFFER_SLOT;
+ } else {
+ BQ_LOGV("releaseBuffer: attempted to release buffer slot %d "
+ "but its state was %d", slot, mSlots[slot].mBufferState);
return BAD_VALUE;
}
- ++current;
- }
- if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
- mSlots[slot].mEglDisplay = eglDisplay;
- mSlots[slot].mEglFence = eglFence;
- mSlots[slot].mFence = releaseFence;
- mSlots[slot].mBufferState = BufferSlot::FREE;
- } else if (mSlots[slot].mNeedsCleanupOnRelease) {
- BQ_LOGV("releaseBuffer: releasing a stale buffer slot %d "
- "(state = %d)", slot, mSlots[slot].mBufferState);
- mSlots[slot].mNeedsCleanupOnRelease = false;
- return STALE_BUFFER_SLOT;
- } else {
- BQ_LOGV("releaseBuffer: attempted to release buffer slot %d "
- "but its state was %d", slot, mSlots[slot].mBufferState);
- return BAD_VALUE;
- }
+ mCore->mDequeueCondition.broadcast();
+ } // Autolock scope
- mCore->mDequeueCondition.broadcast();
+ // Call back without lock held
+ if (listener != NULL) {
+ listener->onBufferReleased();
+ }
return NO_ERROR;
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 40a6cbb..71ba4e7 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -26,6 +26,7 @@
#include <gui/BufferQueueCore.h>
#include <gui/IConsumerListener.h>
#include <gui/IGraphicBufferAlloc.h>
+#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
#include <private/gui/ComposerService.h>
@@ -49,7 +50,7 @@
mConsumerListener(),
mConsumerUsageBits(0),
mConnectedApi(NO_CONNECTED_API),
- mConnectedProducerToken(),
+ mConnectedProducerListener(),
mSlots(),
mQueue(),
mOverrideMaxBufferCount(0),
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9dd90ba..ea37309 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -25,6 +25,7 @@
#include <gui/BufferQueueProducer.h>
#include <gui/IConsumerListener.h>
#include <gui/IGraphicBufferAlloc.h>
+#include <gui/IProducerListener.h>
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -654,7 +655,7 @@
return NO_ERROR;
}
-status_t BufferQueueProducer::connect(const sp<android::IBinder> &token,
+status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput *output) {
ATRACE_CALL();
Mutex::Autolock lock(mCore->mMutex);
@@ -711,16 +712,16 @@
// Set up a death notification so that we can disconnect
// automatically if the remote producer dies
- if (token != NULL && token->remoteBinder() != NULL) {
- status = token->linkToDeath(
+ if (listener != NULL &&
+ listener->asBinder()->remoteBinder() != NULL) {
+ status = listener->asBinder()->linkToDeath(
static_cast<IBinder::DeathRecipient*>(this));
- if (status == NO_ERROR) {
- mCore->mConnectedProducerToken = token;
- } else {
+ if (status != NO_ERROR) {
BQ_LOGE("connect(P): linkToDeath failed: %s (%d)",
strerror(-status), status);
}
}
+ mCore->mConnectedProducerListener = listener;
break;
default:
BQ_LOGE("connect(P): unknown API %d", api);
@@ -759,14 +760,15 @@
mCore->freeAllBuffersLocked();
// Remove our death notification callback if we have one
- sp<IBinder> token = mCore->mConnectedProducerToken;
- if (token != NULL) {
+ if (mCore->mConnectedProducerListener != NULL) {
+ sp<IBinder> token =
+ mCore->mConnectedProducerListener->asBinder();
// This can fail if we're here because of the death
// notification, but we just ignore it
token->unlinkToDeath(
static_cast<IBinder::DeathRecipient*>(this));
}
- mCore->mConnectedProducerToken = NULL;
+ mCore->mConnectedProducerListener = NULL;
mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
mCore->mSidebandStream.clear();
mCore->mDequeueCondition.broadcast();
@@ -793,8 +795,16 @@
}
status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) {
- Mutex::Autolock _l(mCore->mMutex);
- mCore->mSidebandStream = stream;
+ sp<IConsumerListener> listener;
+ { // Autolock scope
+ Mutex::Autolock _l(mCore->mMutex);
+ mCore->mSidebandStream = stream;
+ listener = mCore->mConsumerListener;
+ } // Autolock scope
+
+ if (listener != NULL) {
+ listener->onSidebandStreamChanged();
+ }
return NO_ERROR;
}
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 7ee3081..3215b2f 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -350,20 +350,24 @@
{
status_t err = NO_ERROR;
+ int buf = item.mBuf;
+
if (!mAttached) {
ST_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL "
"ES context");
+ releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
+ mEglDisplay, EGL_NO_SYNC_KHR);
return INVALID_OPERATION;
}
// Confirm state.
err = checkAndUpdateEglStateLocked();
if (err != NO_ERROR) {
+ releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
+ mEglDisplay, EGL_NO_SYNC_KHR);
return err;
}
- int buf = item.mBuf;
-
// If the mEglSlot entry is empty, create an EGLImage for the gralloc
// buffer currently in the slot in ConsumerBase.
//
@@ -377,6 +381,12 @@
if (image == EGL_NO_IMAGE_KHR) {
ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
mEglDisplay, buf);
+ const sp<GraphicBuffer>& gb = mSlots[buf].mGraphicBuffer;
+ ST_LOGW("buffer size=%ux%u st=%u usage=0x%x fmt=%d",
+ gb->getWidth(), gb->getHeight(), gb->getStride(),
+ gb->getUsage(), gb->getPixelFormat());
+ releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
+ mEglDisplay, EGL_NO_SYNC_KHR);
return UNKNOWN_ERROR;
}
mEglSlots[buf].mEglImage = image;
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 7c50315..c0b08c1 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -27,6 +27,7 @@
#include <binder/IInterface.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
namespace android {
// ----------------------------------------------------------------------------
@@ -171,11 +172,16 @@
return result;
}
- virtual status_t connect(const sp<IBinder>& token,
+ virtual status_t connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput* output) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
- data.writeStrongBinder(token);
+ if (listener != NULL) {
+ data.writeInt32(1);
+ data.writeStrongBinder(listener->asBinder());
+ } else {
+ data.writeInt32(0);
+ }
data.writeInt32(api);
data.writeInt32(producerControlledByApp);
status_t result = remote()->transact(CONNECT, data, &reply);
@@ -308,13 +314,16 @@
} break;
case CONNECT: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
- sp<IBinder> token = data.readStrongBinder();
+ sp<IProducerListener> listener;
+ if (data.readInt32() == 1) {
+ listener = IProducerListener::asInterface(data.readStrongBinder());
+ }
int api = data.readInt32();
bool producerControlledByApp = data.readInt32();
QueueBufferOutput* const output =
reinterpret_cast<QueueBufferOutput *>(
reply->writeInplace(sizeof(QueueBufferOutput)));
- status_t res = connect(token, api, producerControlledByApp, output);
+ status_t res = connect(listener, api, producerControlledByApp, output);
reply->writeInt32(res);
return NO_ERROR;
} break;
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
new file mode 100644
index 0000000..efe4069
--- /dev/null
+++ b/libs/gui/IProducerListener.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Parcel.h>
+
+#include <gui/IProducerListener.h>
+
+namespace android {
+
+enum {
+ ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpProducerListener : public BpInterface<IProducerListener>
+{
+public:
+ BpProducerListener(const sp<IBinder>& impl)
+ : BpInterface<IProducerListener>(impl) {}
+
+ virtual void onBufferReleased() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+ remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(ProducerListener, "android.gui.IProducerListener")
+
+status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ switch (code) {
+ case ON_BUFFER_RELEASED:
+ CHECK_INTERFACE(IProducerListener, data, reply);
+ onBufferReleased();
+ return NO_ERROR;
+ }
+ return BBinder::onTransact(code, data, reply, flags);
+}
+
+} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index e96cc54..c067244 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -229,6 +229,21 @@
memcpy(info, reply.readInplace(sizeof(DisplayInfo)), sizeof(DisplayInfo));
return reply.readInt32();
}
+
+ virtual status_t clearAnimationFrameStats() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t getAnimationFrameStats(FrameStats* outStats) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply);
+ reply.read(*outStats);
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -351,6 +366,20 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case CLEAR_ANIMATION_FRAME_STATS: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ status_t result = clearAnimationFrameStats();
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
+ case GET_ANIMATION_FRAME_STATS: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ FrameStats stats;
+ status_t result = getAnimationFrameStats(&stats);
+ reply->write(stats);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 1adc134..3da6423 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -39,7 +39,9 @@
enum {
CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
- DESTROY_SURFACE
+ DESTROY_SURFACE,
+ CLEAR_LAYER_FRAME_STATS,
+ GET_LAYER_FRAME_STATS
};
class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
@@ -73,6 +75,23 @@
remote()->transact(DESTROY_SURFACE, data, &reply);
return reply.readInt32();
}
+
+ virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
+ data.writeStrongBinder(handle);
+ remote()->transact(CLEAR_LAYER_FRAME_STATS, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
+ data.writeStrongBinder(handle);
+ remote()->transact(GET_LAYER_FRAME_STATS, data, &reply);
+ reply.read(*outStats);
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");
@@ -101,7 +120,23 @@
} break;
case DESTROY_SURFACE: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- reply->writeInt32( destroySurface( data.readStrongBinder() ) );
+ reply->writeInt32(destroySurface( data.readStrongBinder() ) );
+ return NO_ERROR;
+ } break;
+ case CLEAR_LAYER_FRAME_STATS: {
+ CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
+ sp<IBinder> handle = data.readStrongBinder();
+ status_t result = clearLayerFrameStats(handle);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ } break;
+ case GET_LAYER_FRAME_STATS: {
+ CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
+ sp<IBinder> handle = data.readStrongBinder();
+ FrameStats stats;
+ status_t result = getLayerFrameStats(handle, &stats);
+ reply->write(stats);
+ reply->writeInt32(result);
return NO_ERROR;
} break;
default:
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index da6b0f9..6f1a3f2 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -48,14 +48,90 @@
mResolution = hwSensor->resolution;
mPower = hwSensor->power;
mMinDelay = hwSensor->minDelay;
+
// Set fifo event count zero for older devices which do not support batching. Fused
// sensors also have their fifo counts set to zero.
if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) {
mFifoReservedEventCount = hwSensor->fifoReservedEventCount;
mFifoMaxEventCount = hwSensor->fifoMaxEventCount;
- } else {
- mFifoReservedEventCount = 0;
- mFifoMaxEventCount = 0;
+ }
+
+ // Ensure existing sensors have correct string type and required
+ // permissions.
+ switch (mType) {
+ case SENSOR_TYPE_ACCELEROMETER:
+ mStringType = SENSOR_STRING_TYPE_ACCELEROMETER;
+ break;
+ case SENSOR_TYPE_AMBIENT_TEMPERATURE:
+ mStringType = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
+ break;
+ case SENSOR_TYPE_GAME_ROTATION_VECTOR:
+ mStringType = SENSOR_STRING_TYPE_GAME_ROTATION_VECTOR;
+ break;
+ case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+ mStringType = SENSOR_STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR;
+ break;
+ case SENSOR_TYPE_GRAVITY:
+ mStringType = SENSOR_STRING_TYPE_GRAVITY;
+ break;
+ case SENSOR_TYPE_GYROSCOPE:
+ mStringType = SENSOR_STRING_TYPE_GYROSCOPE;
+ break;
+ case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+ mStringType = SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED;
+ break;
+ case SENSOR_TYPE_HEART_RATE:
+ mStringType = SENSOR_STRING_TYPE_HEART_RATE;
+ mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS;
+ break;
+ case SENSOR_TYPE_LIGHT:
+ mStringType = SENSOR_STRING_TYPE_LIGHT;
+ break;
+ case SENSOR_TYPE_LINEAR_ACCELERATION:
+ mStringType = SENSOR_STRING_TYPE_LINEAR_ACCELERATION;
+ break;
+ case SENSOR_TYPE_MAGNETIC_FIELD:
+ mStringType = SENSOR_STRING_TYPE_MAGNETIC_FIELD;
+ break;
+ case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+ mStringType = SENSOR_STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
+ break;
+ case SENSOR_TYPE_ORIENTATION:
+ mStringType = SENSOR_STRING_TYPE_ORIENTATION;
+ break;
+ case SENSOR_TYPE_PRESSURE:
+ mStringType = SENSOR_STRING_TYPE_PRESSURE;
+ break;
+ case SENSOR_TYPE_PROXIMITY:
+ mStringType = SENSOR_STRING_TYPE_PROXIMITY;
+ break;
+ case SENSOR_TYPE_RELATIVE_HUMIDITY:
+ mStringType = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
+ break;
+ case SENSOR_TYPE_ROTATION_VECTOR:
+ mStringType = SENSOR_STRING_TYPE_ROTATION_VECTOR;
+ break;
+ case SENSOR_TYPE_SIGNIFICANT_MOTION:
+ mStringType = SENSOR_STRING_TYPE_SIGNIFICANT_MOTION;
+ break;
+ case SENSOR_TYPE_STEP_COUNTER:
+ mStringType = SENSOR_STRING_TYPE_STEP_COUNTER;
+ break;
+ case SENSOR_TYPE_STEP_DETECTOR:
+ mStringType = SENSOR_STRING_TYPE_STEP_DETECTOR;
+ break;
+ case SENSOR_TYPE_TEMPERATURE:
+ mStringType = SENSOR_STRING_TYPE_TEMPERATURE;
+ break;
+ default:
+ // Only pipe the stringType and requiredPermission for custom sensors.
+ if (halVersion >= SENSORS_DEVICE_API_VERSION_1_2 && hwSensor->stringType) {
+ mStringType = hwSensor->stringType;
+ }
+ if (halVersion >= SENSORS_DEVICE_API_VERSION_1_2 && hwSensor->requiredPermission) {
+ mRequiredPermission = hwSensor->requiredPermission;
+ }
+ break;
}
}
@@ -115,6 +191,14 @@
return mFifoMaxEventCount;
}
+const String8& Sensor::getStringType() const {
+ return mStringType;
+}
+
+const String8& Sensor::getRequiredPermission() const {
+ return mRequiredPermission;
+}
+
size_t Sensor::getFlattenedSize() const
{
size_t fixedSize =
@@ -123,8 +207,10 @@
sizeof(int32_t) * 3;
size_t variableSize =
- sizeof(int32_t) + FlattenableUtils::align<4>(mName.length()) +
- sizeof(int32_t) + FlattenableUtils::align<4>(mVendor.length());
+ sizeof(uint32_t) + FlattenableUtils::align<4>(mName.length()) +
+ sizeof(uint32_t) + FlattenableUtils::align<4>(mVendor.length()) +
+ sizeof(uint32_t) + FlattenableUtils::align<4>(mStringType.length()) +
+ sizeof(uint32_t) + FlattenableUtils::align<4>(mRequiredPermission.length());
return fixedSize + variableSize;
}
@@ -134,14 +220,8 @@
return NO_MEMORY;
}
- FlattenableUtils::write(buffer, size, mName.length());
- memcpy(static_cast<char*>(buffer), mName.string(), mName.length());
- FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(mName.length()));
-
- FlattenableUtils::write(buffer, size, mVendor.length());
- memcpy(static_cast<char*>(buffer), mVendor.string(), mVendor.length());
- FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(mVendor.length()));
-
+ flattenString8(buffer, size, mName);
+ flattenString8(buffer, size, mVendor);
FlattenableUtils::write(buffer, size, mVersion);
FlattenableUtils::write(buffer, size, mHandle);
FlattenableUtils::write(buffer, size, mType);
@@ -152,38 +232,23 @@
FlattenableUtils::write(buffer, size, mMinDelay);
FlattenableUtils::write(buffer, size, mFifoReservedEventCount);
FlattenableUtils::write(buffer, size, mFifoMaxEventCount);
+ flattenString8(buffer, size, mStringType);
+ flattenString8(buffer, size, mRequiredPermission);
return NO_ERROR;
}
status_t Sensor::unflatten(void const* buffer, size_t size) {
- size_t len;
-
- if (size < sizeof(size_t)) {
+ if (!unflattenString8(buffer, size, mName)) {
return NO_MEMORY;
}
- FlattenableUtils::read(buffer, size, len);
- if (size < len) {
+ if (!unflattenString8(buffer, size, mVendor)) {
return NO_MEMORY;
}
- mName.setTo(static_cast<char const*>(buffer), len);
- FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
-
-
- if (size < sizeof(size_t)) {
- return NO_MEMORY;
- }
- FlattenableUtils::read(buffer, size, len);
- if (size < len) {
- return NO_MEMORY;
- }
- mVendor.setTo(static_cast<char const*>(buffer), len);
- FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
size_t fixedSize =
sizeof(int32_t) * 3 +
sizeof(float) * 4 +
sizeof(int32_t) * 3;
-
if (size < fixedSize) {
return NO_MEMORY;
}
@@ -198,8 +263,37 @@
FlattenableUtils::read(buffer, size, mMinDelay);
FlattenableUtils::read(buffer, size, mFifoReservedEventCount);
FlattenableUtils::read(buffer, size, mFifoMaxEventCount);
+
+ if (!unflattenString8(buffer, size, mStringType)) {
+ return NO_MEMORY;
+ }
+ if (!unflattenString8(buffer, size, mRequiredPermission)) {
+ return NO_MEMORY;
+ }
return NO_ERROR;
}
+void Sensor::flattenString8(void*& buffer, size_t& size,
+ const String8& string8) {
+ uint32_t len = string8.length();
+ FlattenableUtils::write(buffer, size, len);
+ memcpy(static_cast<char*>(buffer), string8.string(), len);
+ FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
+}
+
+bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& outputString8) {
+ uint32_t len;
+ if (size < sizeof(len)) {
+ return false;
+ }
+ FlattenableUtils::read(buffer, size, len);
+ if (size < len) {
+ return false;
+ }
+ outputString8.setTo(static_cast<char const*>(buffer), len);
+ FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
+ return true;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 95f4084..d1ef503 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -27,6 +27,7 @@
#include <ui/Fence.h>
+#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/GLConsumer.h>
@@ -513,10 +514,10 @@
int Surface::connect(int api) {
ATRACE_CALL();
ALOGV("Surface::connect");
- static sp<BBinder> sLife = new BBinder();
+ static sp<IProducerListener> listener = new DummyProducerListener();
Mutex::Autolock lock(mMutex);
IGraphicBufferProducer::QueueBufferOutput output;
- int err = mGraphicBufferProducer->connect(sLife, api, mProducerControlledByApp, &output);
+ int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
if (err == NO_ERROR) {
uint32_t numPendingBuffers = 0;
output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6b20eaf..b7af415 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -515,6 +515,21 @@
return err;
}
+status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const {
+ if (mStatus != NO_ERROR) {
+ return mStatus;
+ }
+ return mClient->clearLayerFrameStats(token);
+}
+
+status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token,
+ FrameStats* outStats) const {
+ if (mStatus != NO_ERROR) {
+ return mStatus;
+ }
+ return mClient->getLayerFrameStats(token, outStats);
+}
+
inline Composer& SurfaceComposerClient::getComposer() {
return mComposer;
}
@@ -622,6 +637,14 @@
ComposerService::getComposerService()->unblank(token);
}
+status_t SurfaceComposerClient::clearAnimationFrameStats() {
+ return ComposerService::getComposerService()->clearAnimationFrameStats();
+}
+
+status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) {
+ return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
+}
+
// ----------------------------------------------------------------------------
status_t ScreenshotClient::capture(
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index de182ee..7c6dfb8 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -156,6 +156,20 @@
return client->setCrop(mHandle, crop);
}
+status_t SurfaceControl::clearLayerFrameStats() const {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->clearLayerFrameStats(mHandle);
+}
+
+status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->getLayerFrameStats(mHandle, outStats);
+}
+
status_t SurfaceControl::validate() const
{
if (mHandle==0 || mClient==0) {
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 7943476..fe8f8b1 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -17,17 +17,19 @@
#define LOG_TAG "BufferQueue_test"
//#define LOG_NDEBUG 0
-#include <gtest/gtest.h>
-
-#include <utils/String8.h>
-#include <utils/threads.h>
+#include <gui/BufferQueue.h>
+#include <gui/IProducerListener.h>
#include <ui/GraphicBuffer.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
-#include <gui/BufferQueue.h>
+
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include <gtest/gtest.h>
namespace android {
@@ -81,12 +83,12 @@
if (forkPid == 0) {
// Child process
- sp<BnGraphicBufferProducer> producer;
- sp<BnGraphicBufferConsumer> consumer;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
sp<IServiceManager> serviceManager = defaultServiceManager();
- serviceManager->addService(PRODUCER_NAME, producer.get());
- serviceManager->addService(CONSUMER_NAME, consumer.get());
+ serviceManager->addService(PRODUCER_NAME, producer->asBinder());
+ serviceManager->addService(CONSUMER_NAME, consumer->asBinder());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
LOG_ALWAYS_FATAL("Shouldn't be here");
@@ -141,7 +143,8 @@
sp<DummyConsumer> dc(new DummyConsumer);
mConsumer->consumerConnect(dc, false);
IGraphicBufferProducer::QueueBufferOutput qbo;
- mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &qbo);
+ mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
+ &qbo);
mProducer->setBufferCount(4);
int slot;
@@ -207,8 +210,8 @@
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
IGraphicBufferProducer::QueueBufferOutput output;
- ASSERT_EQ(OK,
- mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+ ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+ NATIVE_WINDOW_API_CPU, false, &output));
ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(-1)); // Index too low
ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(
@@ -260,8 +263,8 @@
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
IGraphicBufferProducer::QueueBufferOutput output;
- ASSERT_EQ(OK,
- mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+ ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+ NATIVE_WINDOW_API_CPU, false, &output));
int slot;
sp<Fence> fence;
@@ -318,8 +321,8 @@
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
IGraphicBufferProducer::QueueBufferOutput output;
- ASSERT_EQ(OK,
- mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+ ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+ NATIVE_WINDOW_API_CPU, false, &output));
int slot;
sp<Fence> fence;
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 9f61a09..abd3724 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -64,11 +64,13 @@
test_info->name(),
params.width, params.height,
params.maxLockedBuffers, params.format);
- sp<BufferQueue> bq = new BufferQueue();
- mCC = new CpuConsumer(bq, params.maxLockedBuffers);
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mCC = new CpuConsumer(consumer, params.maxLockedBuffers);
String8 name("CpuConsumer_Under_Test");
mCC->setName(name);
- mSTC = new Surface(bq);
+ mSTC = new Surface(producer);
mANW = mSTC;
}
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index c2653c2..aadfe61 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -25,13 +25,14 @@
#include <ui/GraphicBuffer.h>
#include <gui/BufferQueue.h>
+#include <gui/IProducerListener.h>
#include <vector>
#define ASSERT_OK(x) ASSERT_EQ(OK, (x))
#define EXPECT_OK(x) EXPECT_EQ(OK, (x))
-#define TEST_TOKEN ((IBinder*)(NULL))
+#define TEST_TOKEN ((IProducerListener*)(NULL))
#define TEST_API NATIVE_WINDOW_API_CPU
#define TEST_API_OTHER NATIVE_WINDOW_API_EGL // valid API that's not TEST_API
#define TEST_CONTROLLED_BY_APP false
@@ -80,11 +81,9 @@
ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
testInfo->name());
- mBQ = new BufferQueue();
mDC = new DummyConsumer;
- mProducer = mBQ;
- mConsumer = mBQ;
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
// Test check: Can't connect producer if no consumer yet
ASSERT_EQ(NO_INIT, TryConnectProducer());
@@ -201,7 +200,6 @@
}
private: // hide from test body
- sp<BufferQueue> mBQ;
sp<DummyConsumer> mDC;
protected: // accessible from test body
diff --git a/libs/gui/tests/MultiTextureConsumer_test.cpp b/libs/gui/tests/MultiTextureConsumer_test.cpp
index 853c25c..1eb6ef6 100644
--- a/libs/gui/tests/MultiTextureConsumer_test.cpp
+++ b/libs/gui/tests/MultiTextureConsumer_test.cpp
@@ -34,9 +34,11 @@
virtual void SetUp() {
GLTest::SetUp();
- sp<BufferQueue> bq = new BufferQueue();
- mGlConsumer = new GLConsumer(bq, TEX_ID);
- mSurface = new Surface(bq);
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mGlConsumer = new GLConsumer(consumer, TEX_ID);
+ mSurface = new Surface(producer);
mANW = mSurface.get();
}
diff --git a/libs/gui/tests/SRGB_test.cpp b/libs/gui/tests/SRGB_test.cpp
index 1077c9d..2d5b8aa 100644
--- a/libs/gui/tests/SRGB_test.cpp
+++ b/libs/gui/tests/SRGB_test.cpp
@@ -68,13 +68,15 @@
}
virtual void SetUp() {
- mBufferQueue = new BufferQueue();
- ASSERT_EQ(NO_ERROR, mBufferQueue->setDefaultBufferSize(
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ ASSERT_EQ(NO_ERROR, consumer->setDefaultBufferSize(
DISPLAY_WIDTH, DISPLAY_HEIGHT));
- mCpuConsumer = new CpuConsumer(mBufferQueue, 1);
+ mCpuConsumer = new CpuConsumer(consumer, 1);
String8 name("CpuConsumer_for_SRGBTest");
mCpuConsumer->setName(name);
- mInputSurface = new Surface(mBufferQueue);
+ mInputSurface = new Surface(producer);
ASSERT_NO_FATAL_FAILURE(createEGLSurface(mInputSurface.get()));
ASSERT_NO_FATAL_FAILURE(createDebugSurface());
@@ -222,7 +224,6 @@
}
// Primary producer and consumer
- sp<BufferQueue> mBufferQueue;
sp<Surface> mInputSurface;
sp<CpuConsumer> mCpuConsumer;
CpuConsumer::LockedBuffer mLockedBuffer;
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 989fcef..7f9fcc4 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -43,9 +43,11 @@
ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
testInfo->name());
- sp<BufferQueue> bq = new BufferQueue();
- mST = new GLConsumer(bq, 123);
- mSTC = new Surface(bq);
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mST = new GLConsumer(consumer, 123);
+ mSTC = new Surface(producer);
mANW = mSTC;
// We need a valid GL context so we can test updateTexImage()
@@ -711,9 +713,11 @@
ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
- sp<BufferQueue> bq = new BufferQueue();
- sp<GLConsumer> st(new GLConsumer(bq, i));
- sp<Surface> stc(new Surface(bq));
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ sp<GLConsumer> st(new GLConsumer(consumer, i));
+ sp<Surface> stc(new Surface(producer));
mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
static_cast<ANativeWindow*>(stc.get()), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
diff --git a/libs/gui/tests/SurfaceTextureGL.h b/libs/gui/tests/SurfaceTextureGL.h
index ac112c4..3bff192 100644
--- a/libs/gui/tests/SurfaceTextureGL.h
+++ b/libs/gui/tests/SurfaceTextureGL.h
@@ -37,10 +37,10 @@
void SetUp() {
GLTest::SetUp();
- sp<BufferQueue> bq = new BufferQueue();
- mBQ = bq;
- mST = new GLConsumer(bq, TEX_ID);
- mSTC = new Surface(bq);
+ sp<IGraphicBufferProducer> producer;
+ BufferQueue::createBufferQueue(&producer, &mConsumer);
+ mST = new GLConsumer(mConsumer, TEX_ID);
+ mSTC = new Surface(producer);
mANW = mSTC;
mTextureRenderer = new TextureRenderer(TEX_ID, mST);
ASSERT_NO_FATAL_FAILURE(mTextureRenderer->SetUp());
@@ -60,7 +60,7 @@
mTextureRenderer->drawTexture();
}
- sp<BufferQueue> mBQ;
+ sp<IGraphicBufferConsumer> mConsumer;
sp<GLConsumer> mST;
sp<Surface> mSTC;
sp<ANativeWindow> mANW;
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index 25b2319..fa1e1b7 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -451,7 +451,7 @@
};
sp<DisconnectWaiter> dw(new DisconnectWaiter());
- mBQ->consumerConnect(dw, false);
+ mConsumer->consumerConnect(dw, false);
sp<Thread> pt(new ProducerThread(mANW));
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 4b6e603..bf87fad 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -88,11 +88,13 @@
sp<ANativeWindow> anw(mSurface);
// Verify the screenshot works with no protected buffers.
- sp<BufferQueue> bq = new BufferQueue();
- sp<CpuConsumer> consumer = new CpuConsumer(bq, 1);
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, bq,
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer,
64, 64, 0, 0x7fffffff, false));
// Set the PROTECTED usage bit and verify that the screenshot fails. Note
@@ -121,7 +123,7 @@
&buf));
ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
}
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, bq,
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer,
64, 64, 0, 0x7fffffff, false));
}
@@ -136,10 +138,12 @@
TEST_F(SurfaceTest, QueryConsumerUsage) {
const int TEST_USAGE_FLAGS =
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
- sp<BufferQueue> bq = new BufferQueue();
- sp<BufferItemConsumer> c = new BufferItemConsumer(bq,
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ sp<BufferItemConsumer> c = new BufferItemConsumer(consumer,
TEST_USAGE_FLAGS);
- sp<Surface> s = new Surface(bq);
+ sp<Surface> s = new Surface(producer);
sp<ANativeWindow> anw(s);
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 008446b..eec97be 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -18,6 +18,7 @@
LOCAL_SRC_FILES:= \
Fence.cpp \
FramebufferNativeWindow.cpp \
+ FrameStats.cpp \
GraphicBuffer.cpp \
GraphicBufferAllocator.cpp \
GraphicBufferMapper.cpp \
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index 93ec0ce..3c0306c 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -138,7 +138,7 @@
if (size < getFlattenedSize() || count < getFdCount()) {
return NO_MEMORY;
}
- FlattenableUtils::write(buffer, size, getFdCount());
+ FlattenableUtils::write(buffer, size, (uint32_t)getFdCount());
if (isValid()) {
*fds++ = mFenceFd;
count--;
@@ -156,7 +156,7 @@
return NO_MEMORY;
}
- size_t numFds;
+ uint32_t numFds;
FlattenableUtils::read(buffer, size, numFds);
if (numFds > 1) {
diff --git a/libs/ui/FrameStats.cpp b/libs/ui/FrameStats.cpp
new file mode 100644
index 0000000..acbe27e
--- /dev/null
+++ b/libs/ui/FrameStats.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 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 <ui/FrameStats.h>
+
+namespace android {
+
+bool FrameStats::isFixedSize() const {
+ return false;
+}
+
+size_t FrameStats::getFlattenedSize() const {
+ const size_t timestampSize = sizeof(nsecs_t);
+
+ size_t size = timestampSize;
+ size += 3 * desiredPresentTimesNano.size() * timestampSize;
+
+ return size;
+}
+
+status_t FrameStats::flatten(void* buffer, size_t size) const {
+ if (size < getFlattenedSize()) {
+ return NO_MEMORY;
+ }
+
+ nsecs_t* timestamps = reinterpret_cast<nsecs_t*>(buffer);
+ const size_t timestampSize = sizeof(nsecs_t);
+ size_t frameCount = desiredPresentTimesNano.size();
+
+ memcpy(timestamps, &refreshPeriodNano, timestampSize);
+ timestamps += 1;
+
+ memcpy(timestamps, desiredPresentTimesNano.array(), frameCount * timestampSize);
+ timestamps += frameCount;
+
+ memcpy(timestamps, actualPresentTimesNano.array(), frameCount * timestampSize);
+ timestamps += frameCount;
+
+ memcpy(timestamps, frameReadyTimesNano.array(), frameCount * timestampSize);
+
+ return NO_ERROR;
+}
+
+status_t FrameStats::unflatten(void const* buffer, size_t size) {
+ const size_t timestampSize = sizeof(nsecs_t);
+
+ if (size < timestampSize) {
+ return NO_MEMORY;
+ }
+
+ nsecs_t const* timestamps = reinterpret_cast<nsecs_t const*>(buffer);
+ size_t frameCount = (size - timestampSize) / (3 * timestampSize);
+
+ memcpy(&refreshPeriodNano, timestamps, timestampSize);
+ timestamps += 1;
+
+ desiredPresentTimesNano.resize(frameCount);
+ memcpy(desiredPresentTimesNano.editArray(), timestamps, frameCount * timestampSize);
+ timestamps += frameCount;
+
+ actualPresentTimesNano.resize(frameCount);
+ memcpy(actualPresentTimesNano.editArray(), timestamps, frameCount * timestampSize);
+ timestamps += frameCount;
+
+ frameReadyTimesNano.resize(frameCount);
+ memcpy(frameReadyTimesNano.editArray(), timestamps, frameCount * timestampSize);
+
+ return NO_ERROR;
+}
+
+} // namespace android
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index c4e4efa..99601ed 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -34,9 +34,17 @@
// Buffer and implementation of ANativeWindowBuffer
// ===========================================================================
+static uint64_t getUniqueId() {
+ static volatile int32_t nextId = 0;
+ uint64_t id = static_cast<uint64_t>(getpid()) << 32;
+ id |= static_cast<uint32_t>(android_atomic_inc(&nextId));
+ return id;
+}
+
GraphicBuffer::GraphicBuffer()
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
- mInitCheck(NO_ERROR) {
+ mInitCheck(NO_ERROR), mId(getUniqueId())
+{
width =
height =
stride =
@@ -48,7 +56,7 @@
GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
PixelFormat reqFormat, uint32_t reqUsage)
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
- mInitCheck(NO_ERROR)
+ mInitCheck(NO_ERROR), mId(getUniqueId())
{
width =
height =
@@ -64,7 +72,7 @@
uint32_t inStride, native_handle_t* inHandle, bool keepOwnership)
: BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
mBufferMapper(GraphicBufferMapper::get()),
- mInitCheck(NO_ERROR)
+ mInitCheck(NO_ERROR), mId(getUniqueId())
{
width = w;
height = h;
@@ -77,7 +85,7 @@
GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership)
: BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
mBufferMapper(GraphicBufferMapper::get()),
- mInitCheck(NO_ERROR), mWrappedBuffer(buffer)
+ mInitCheck(NO_ERROR), mWrappedBuffer(buffer), mId(getUniqueId())
{
width = buffer->width;
height = buffer->height;
@@ -201,7 +209,7 @@
}
size_t GraphicBuffer::getFlattenedSize() const {
- return (8 + (handle ? handle->numInts : 0))*sizeof(int);
+ return (10 + (handle ? handle->numInts : 0))*sizeof(int);
}
size_t GraphicBuffer::getFdCount() const {
@@ -215,22 +223,24 @@
size_t fdCountNeeded = GraphicBuffer::getFdCount();
if (count < fdCountNeeded) return NO_MEMORY;
- int* buf = static_cast<int*>(buffer);
+ int32_t* buf = static_cast<int32_t*>(buffer);
buf[0] = 'GBFR';
buf[1] = width;
buf[2] = height;
buf[3] = stride;
buf[4] = format;
buf[5] = usage;
- buf[6] = 0;
- buf[7] = 0;
+ buf[6] = static_cast<int32_t>(mId >> 32);
+ buf[7] = static_cast<int32_t>(mId & 0xFFFFFFFFull);
+ buf[8] = 0;
+ buf[9] = 0;
if (handle) {
- buf[6] = handle->numFds;
- buf[7] = handle->numInts;
+ buf[8] = handle->numFds;
+ buf[9] = handle->numInts;
native_handle_t const* const h = handle;
memcpy(fds, h->data, h->numFds*sizeof(int));
- memcpy(&buf[8], h->data + h->numFds, h->numInts*sizeof(int));
+ memcpy(&buf[10], h->data + h->numFds, h->numInts*sizeof(int));
}
buffer = reinterpret_cast<void*>(static_cast<int*>(buffer) + sizeNeeded);
@@ -250,10 +260,10 @@
int const* buf = static_cast<int const*>(buffer);
if (buf[0] != 'GBFR') return BAD_TYPE;
- const size_t numFds = buf[6];
- const size_t numInts = buf[7];
+ const size_t numFds = buf[8];
+ const size_t numInts = buf[9];
- const size_t sizeNeeded = (8 + numInts) * sizeof(int);
+ const size_t sizeNeeded = (10 + numInts) * sizeof(int);
if (size < sizeNeeded) return NO_MEMORY;
size_t fdCountNeeded = 0;
@@ -272,13 +282,16 @@
usage = buf[5];
native_handle* h = native_handle_create(numFds, numInts);
memcpy(h->data, fds, numFds*sizeof(int));
- memcpy(h->data + numFds, &buf[8], numInts*sizeof(int));
+ memcpy(h->data + numFds, &buf[10], numInts*sizeof(int));
handle = h;
} else {
width = height = stride = format = usage = 0;
handle = NULL;
}
+ mId = static_cast<uint64_t>(buf[6]) << 32;
+ mId |= static_cast<uint32_t>(buf[7]);
+
mOwner = ownHandle;
if (handle != 0) {
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 67fbae5..44b5560 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -222,7 +222,7 @@
}
char value[PROPERTY_VALUE_MAX];
property_get("debug.egl.callstack", value, "0");
- if (atoi(value)) {
+ if (true || atoi(value)) {
CallStack stack(LOG_TAG);
}
}
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index fea52f3..a4364c6 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -107,9 +107,11 @@
};
// Create a EGLSurface
- sp<BufferQueue> bq = new BufferQueue();
- bq->consumerConnect(new DummyConsumer, false);
- sp<Surface> mSTC = new Surface(static_cast<sp<IGraphicBufferProducer> >( bq));
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config,
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index dbfc957..f219f95 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -251,10 +251,10 @@
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
- // Reset the key repeat timer whenever we disallow key events, even if the next event
- // is not a key. This is to ensure that we abort a key repeat if the device is just coming
- // out of sleep.
- if (!mPolicy->isKeyRepeatEnabled()) {
+ // Reset the key repeat timer whenever normal dispatch is suspended while the
+ // device is in a non-interactive state. This is to ensure that we abort a key
+ // repeat if the device is just coming out of sleep.
+ if (!mDispatchEnabled) {
resetKeyRepeatLocked();
}
@@ -1138,30 +1138,6 @@
// For security reasons, we defer updating the touch state until we are sure that
// event injection will be allowed.
- //
- // FIXME In the original code, screenWasOff could never be set to true.
- // The reason is that the POLICY_FLAG_WOKE_HERE
- // and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw
- // EV_KEY, EV_REL and EV_ABS events. As it happens, the touch event was
- // actually enqueued using the policyFlags that appeared in the final EV_SYN
- // events upon which no preprocessing took place. So policyFlags was always 0.
- // In the new native input dispatcher we're a bit more careful about event
- // preprocessing so the touches we receive can actually have non-zero policyFlags.
- // Unfortunately we obtain undesirable behavior.
- //
- // Here's what happens:
- //
- // When the device dims in anticipation of going to sleep, touches
- // in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause
- // the device to brighten and reset the user activity timer.
- // Touches on other windows (such as the launcher window)
- // are dropped. Then after a moment, the device goes to sleep. Oops.
- //
- // Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE
- // instead of POLICY_FLAG_WOKE_HERE...
- //
- bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE;
-
int32_t displayId = entry->displayId;
int32_t action = entry->action;
int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
@@ -1246,10 +1222,7 @@
isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
| InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
- if (! screenWasOff
- || (flags & InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING)) {
- newTouchedWindowHandle = windowHandle;
- }
+ newTouchedWindowHandle = windowHandle;
break; // found touched window, exit window loop
}
}
@@ -2412,10 +2385,6 @@
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
- if (policyFlags & POLICY_FLAG_WOKE_HERE) {
- flags |= AKEY_EVENT_FLAG_WOKE_HERE;
- }
-
bool needWake;
{ // acquire lock
mLock.lock();
@@ -2595,10 +2564,6 @@
mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
}
- if (policyFlags & POLICY_FLAG_WOKE_HERE) {
- flags |= AKEY_EVENT_FLAG_WOKE_HERE;
- }
-
mLock.lock();
firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(),
keyEvent->getDeviceId(), keyEvent->getSource(),
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 29854b2..9439124 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -211,9 +211,6 @@
/* Gets the input dispatcher configuration. */
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
- /* Returns true if automatic key repeating is enabled. */
- virtual bool isKeyRepeatEnabled() = 0;
-
/* Filters an input event.
* Return true to dispatch the event unmodified, false to consume the event.
* A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index fc89a9b..7aac6ed 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -65,10 +65,6 @@
*outConfig = mConfig;
}
- virtual bool isKeyRepeatEnabled() {
- return true;
- }
-
virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
return true;
}
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index f0bfe2c..8837a4d 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -206,7 +206,7 @@
String8 result;
if (!PermissionCache::checkCallingPermission(sDump)) {
result.appendFormat("Permission Denial: "
- "can't dump SurfaceFlinger from pid=%d, uid=%d\n",
+ "can't dump SensorService from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
} else {
@@ -216,21 +216,24 @@
const Sensor& s(mSensorList[i]);
const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle()));
result.appendFormat(
- "%-48s| %-32s | 0x%08x | ",
+ "%-48s| %-32s| %-48s| 0x%08x | \"%s\"\n\t",
s.getName().string(),
s.getVendor().string(),
- s.getHandle());
+ s.getStringType().string(),
+ s.getHandle(),
+ s.getRequiredPermission().string());
if (s.getMinDelay() > 0) {
result.appendFormat(
- "maxRate=%7.2fHz | ", 1e6f / s.getMinDelay());
+ "maxRate=%7.2fHz | ", 1e6f / s.getMinDelay());
} else {
result.append(s.getMinDelay() == 0
? "on-demand | "
: "one-shot | ");
}
if (s.getFifoMaxEventCount() > 0) {
- result.appendFormat("getFifoMaxEventCount=%d events | ", s.getFifoMaxEventCount());
+ result.appendFormat("FifoMax=%d events | ",
+ s.getFifoMaxEventCount());
} else {
result.append("no batching support | ");
}
@@ -491,10 +494,23 @@
{
char value[PROPERTY_VALUE_MAX];
property_get("debug.sensors", value, "0");
- if (atoi(value)) {
- return mUserSensorListDebug;
+ const Vector<Sensor>& initialSensorList = (atoi(value)) ?
+ mUserSensorListDebug : mUserSensorList;
+ Vector<Sensor> accessibleSensorList;
+ for (size_t i = 0; i < initialSensorList.size(); i++) {
+ Sensor sensor = initialSensorList[i];
+ if (canAccessSensor(sensor)) {
+ accessibleSensorList.add(sensor);
+ } else {
+ String8 infoMessage;
+ infoMessage.appendFormat(
+ "Skipped sensor %s because it requires permission %s",
+ sensor.getName().string(),
+ sensor.getRequiredPermission().string());
+ ALOGI(infoMessage.string());
+ }
}
- return mUserSensorList;
+ return accessibleSensorList;
}
sp<ISensorEventConnection> SensorService::createSensorEventConnection()
@@ -540,6 +556,10 @@
BatteryService::cleanup(c->getUid());
}
+Sensor SensorService::getSensorFromHandle(int handle) const {
+ return mSensorMap.valueFor(handle)->getSensor();
+}
+
status_t SensorService::enable(const sp<SensorEventConnection>& connection,
int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags)
{
@@ -550,6 +570,11 @@
if (sensor == NULL) {
return BAD_VALUE;
}
+
+ if (!verifyCanAccessSensor(sensor->getSensor(), "Tried enabling")) {
+ return BAD_VALUE;
+ }
+
Mutex::Autolock _l(mLock);
SensorRecord* rec = mActiveSensors.valueFor(handle);
if (rec == 0) {
@@ -671,6 +696,10 @@
if (!sensor)
return BAD_VALUE;
+ if (!verifyCanAccessSensor(sensor->getSensor(), "Tried configuring")) {
+ return BAD_VALUE;
+ }
+
if (ns < 0)
return BAD_VALUE;
@@ -684,17 +713,44 @@
status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection,
int handle) {
- if (mInitCheck != NO_ERROR) return mInitCheck;
- SensorInterface* sensor = mSensorMap.valueFor(handle);
- if (sensor == NULL) {
- return BAD_VALUE;
- }
- if (sensor->getSensor().getType() == SENSOR_TYPE_SIGNIFICANT_MOTION) {
- ALOGE("flush called on Significant Motion sensor");
- return INVALID_OPERATION;
- }
- return sensor->flush(connection.get(), handle);
+ if (mInitCheck != NO_ERROR) return mInitCheck;
+ SensorInterface* sensor = mSensorMap.valueFor(handle);
+ if (sensor == NULL) {
+ return BAD_VALUE;
+ }
+
+ if (!verifyCanAccessSensor(sensor->getSensor(), "Tried flushing")) {
+ return BAD_VALUE;
+ }
+
+ if (sensor->getSensor().getType() == SENSOR_TYPE_SIGNIFICANT_MOTION) {
+ ALOGE("flush called on Significant Motion sensor");
+ return INVALID_OPERATION;
+ }
+ return sensor->flush(connection.get(), handle);
}
+
+
+bool SensorService::canAccessSensor(const Sensor& sensor) {
+ String16 permissionString(sensor.getRequiredPermission());
+ return permissionString.size() == 0 ||
+ PermissionCache::checkCallingPermission(permissionString);
+}
+
+bool SensorService::verifyCanAccessSensor(const Sensor& sensor, const char* operation) {
+ if (canAccessSensor(sensor)) {
+ return true;
+ } else {
+ String8 errorMessage;
+ errorMessage.appendFormat(
+ "%s a sensor (%s) without holding its required permission: %s",
+ operation,
+ sensor.getName().string(),
+ sensor.getRequiredPermission().string());
+ return false;
+ }
+}
+
// ---------------------------------------------------------------------------
SensorService::SensorRecord::SensorRecord(
@@ -763,6 +819,9 @@
bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
Mutex::Autolock _l(mConnectionLock);
+ if (!verifyCanAccessSensor(mService->getSensorFromHandle(handle), "Tried adding")) {
+ return false;
+ }
if (mSensorInfo.indexOfKey(handle) < 0) {
mSensorInfo.add(handle, FlushInfo());
return true;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 1dc2dd3..e88ffc8 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -131,6 +131,7 @@
String8 getSensorName(int handle) const;
bool isVirtualSensor(int handle) const;
+ Sensor getSensorFromHandle(int handle) const;
void recordLastValue(const sensors_event_t* buffer, size_t count);
static void sortEventBuffer(sensors_event_t* buffer, size_t count);
Sensor registerSensor(SensorInterface* sensor);
@@ -141,7 +142,8 @@
const sp<SensorEventConnection>& connection, int handle);
void cleanupAutoDisabledSensor(const sp<SensorEventConnection>& connection,
sensors_event_t const* buffer, const int count);
-
+ static bool canAccessSensor(const Sensor& sensor);
+ static bool verifyCanAccessSensor(const Sensor& sensor, const char* operation);
// constants
Vector<Sensor> mSensorList;
Vector<Sensor> mUserSensorListDebug;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 975631c..f7d32d0 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -155,5 +155,23 @@
return mFlinger->onLayerRemoved(this, handle);
}
+status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
+ sp<Layer> layer = getLayerUser(handle);
+ if (layer == NULL) {
+ return NAME_NOT_FOUND;
+ }
+ layer->clearFrameStats();
+ return NO_ERROR;
+}
+
+status_t Client::getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
+ sp<Layer> layer = getLayerUser(handle);
+ if (layer == NULL) {
+ return NAME_NOT_FOUND;
+ }
+ layer->getFrameStats(outStats);
+ return NO_ERROR;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 84e649f..b6d7381 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -60,6 +60,10 @@
virtual status_t destroySurface(const sp<IBinder>& handle);
+ virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
+
+ virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
+
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index f4cb8b5..67229d5 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -454,11 +454,12 @@
return mSource[SOURCE_SINK]->query(what, value);
}
-status_t VirtualDisplaySurface::connect(const sp<IBinder>& token,
+status_t VirtualDisplaySurface::connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp,
QueueBufferOutput* output) {
QueueBufferOutput qbo;
- status_t result = mSource[SOURCE_SINK]->connect(token, api, producerControlledByApp, &qbo);
+ status_t result = mSource[SOURCE_SINK]->connect(listener, api,
+ producerControlledByApp, &qbo);
if (result == NO_ERROR) {
updateQueueBufferOutput(qbo);
*output = mQueueBufferOutput;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 09e5544..165224a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -27,6 +27,7 @@
// ---------------------------------------------------------------------------
class HWComposer;
+class IProducerListener;
/* This DisplaySurface implementation supports virtual displays, where GLES
* and/or HWC compose into a buffer that is then passed to an arbitrary
@@ -105,7 +106,7 @@
const QueueBufferInput& input, QueueBufferOutput* output);
virtual void cancelBuffer(int pslot, const sp<Fence>& fence);
virtual int query(int what, int* value);
- virtual status_t connect(const sp<IBinder>& token,
+ virtual status_t connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput* output);
virtual status_t disconnect(int api);
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index 2fb665e..c09bbe4 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -22,6 +22,7 @@
#include <cutils/log.h>
#include <ui/Fence.h>
+#include <ui/FrameStats.h>
#include <utils/String8.h>
@@ -100,7 +101,7 @@
processFencesLocked();
}
-void FrameTracker::clear() {
+void FrameTracker::clearStats() {
Mutex::Autolock lock(mMutex);
for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) {
mFrameRecords[i].desiredPresentTime = 0;
@@ -115,6 +116,32 @@
mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
}
+void FrameTracker::getStats(FrameStats* outStats) const {
+ Mutex::Autolock lock(mMutex);
+ processFencesLocked();
+
+ outStats->refreshPeriodNano = mDisplayPeriod;
+
+ const size_t offset = mOffset;
+ for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
+ const size_t index = (offset + i) % NUM_FRAME_RECORDS;
+
+ // Skip frame records with no data (if buffer not yet full).
+ if (mFrameRecords[index].desiredPresentTime == 0) {
+ continue;
+ }
+
+ nsecs_t desiredPresentTimeNano = mFrameRecords[index].desiredPresentTime;
+ outStats->desiredPresentTimesNano.push_back(desiredPresentTimeNano);
+
+ nsecs_t actualPresentTimeNano = mFrameRecords[index].actualPresentTime;
+ outStats->actualPresentTimesNano.push_back(actualPresentTimeNano);
+
+ nsecs_t frameReadyTimeNano = mFrameRecords[index].frameReadyTime;
+ outStats->frameReadyTimesNano.push_back(frameReadyTimeNano);
+ }
+}
+
void FrameTracker::logAndResetStats(const String8& name) {
Mutex::Autolock lock(mMutex);
logStatsLocked(name);
@@ -206,7 +233,7 @@
mFrameRecords[idx].actualPresentTime < INT64_MAX;
}
-void FrameTracker::dump(String8& result) const {
+void FrameTracker::dumpStats(String8& result) const {
Mutex::Autolock lock(mMutex);
processFencesLocked();
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index 9233247..cd5e3f3 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -78,15 +78,18 @@
// advanceFrame advances the frame tracker to the next frame.
void advanceFrame();
- // clear resets all the tracked frame data to zero.
- void clear();
+ // clearStats clears the tracked frame stats.
+ void clearStats();
+
+ // getStats gets the tracked frame stats.
+ void getStats(FrameStats* outStats) const;
// logAndResetStats dumps the current statistics to the binary event log
// and then resets the accumulated statistics to their initial values.
void logAndResetStats(const String8& name);
- // dump appends the current frame display time history to the result string.
- void dump(String8& result) const;
+ // dumpStats dump appends the current frame display time history to the result string.
+ void dumpStats(String8& result) const;
private:
struct FrameRecord {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7f2ee2a..1b86204 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -117,8 +117,8 @@
void Layer::onFirstRef() {
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
- sp<BnGraphicBufferProducer> producer;
- sp<BnGraphicBufferConsumer> consumer;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
mProducer = new MonitoredProducer(producer, mFlinger);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
@@ -959,7 +959,7 @@
bool Layer::isVisible() const {
const Layer::State& s(mDrawingState);
return !(s.flags & layer_state_t::eLayerHidden) && s.alpha
- && (mActiveBuffer != NULL);
+ && (mActiveBuffer != NULL || mSidebandStream != NULL);
}
Region Layer::latchBuffer(bool& recomputeVisibleRegions)
@@ -1244,18 +1244,22 @@
}
}
-void Layer::dumpStats(String8& result) const {
- mFrameTracker.dump(result);
+void Layer::dumpFrameStats(String8& result) const {
+ mFrameTracker.dumpStats(result);
}
-void Layer::clearStats() {
- mFrameTracker.clear();
+void Layer::clearFrameStats() {
+ mFrameTracker.clearStats();
}
void Layer::logFrameStats() {
mFrameTracker.logAndResetStats(mName);
}
+void Layer::getFrameStats(FrameStats* outStats) const {
+ mFrameTracker.getStats(outStats);
+}
+
// ---------------------------------------------------------------------------
Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8f8989e..62970c3 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -27,6 +27,7 @@
#include <utils/String8.h>
#include <utils/Timers.h>
+#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
@@ -288,9 +289,10 @@
/* always call base class first */
void dump(String8& result, Colorizer& colorizer) const;
- void dumpStats(String8& result) const;
- void clearStats();
+ void dumpFrameStats(String8& result) const;
+ void clearFrameStats();
void logFrameStats();
+ void getFrameStats(FrameStats* outStats) const;
protected:
// constant
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 8fed676..1a2b7e5 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -20,7 +20,7 @@
namespace android {
-MonitoredProducer::MonitoredProducer(const sp<BnGraphicBufferProducer>& producer,
+MonitoredProducer::MonitoredProducer(const sp<IGraphicBufferProducer>& producer,
const sp<SurfaceFlinger>& flinger) :
mProducer(producer),
mFlinger(flinger) {}
@@ -49,8 +49,7 @@
wp<IBinder> mProducer;
};
- mFlinger->postMessageAsync(new MessageCleanUpList(mFlinger,
- static_cast<BnGraphicBufferProducer*>(this)));
+ mFlinger->postMessageAsync(new MessageCleanUpList(mFlinger, asBinder()));
}
status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
@@ -88,9 +87,9 @@
return mProducer->query(what, value);
}
-status_t MonitoredProducer::connect(const sp<IBinder>& token, int api,
- bool producerControlledByApp, QueueBufferOutput* output) {
- return mProducer->connect(token, api, producerControlledByApp, output);
+status_t MonitoredProducer::connect(const sp<IProducerListener>& listener,
+ int api, bool producerControlledByApp, QueueBufferOutput* output) {
+ return mProducer->connect(listener, api, producerControlledByApp, output);
}
status_t MonitoredProducer::disconnect(int api) {
@@ -101,5 +100,9 @@
return mProducer->setSidebandStream(stream);
}
+IBinder* MonitoredProducer::onAsBinder() {
+ return mProducer->asBinder().get();
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index f78be20..1e6431e 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -21,15 +21,15 @@
namespace android {
-class IBinder;
+class IProducerListener;
class NativeHandle;
class SurfaceFlinger;
// MonitoredProducer wraps an IGraphicBufferProducer so that SurfaceFlinger will
// be notified upon its destruction
-class MonitoredProducer : public BnGraphicBufferProducer {
+class MonitoredProducer : public IGraphicBufferProducer {
public:
- MonitoredProducer(const sp<BnGraphicBufferProducer>& producer,
+ MonitoredProducer(const sp<IGraphicBufferProducer>& producer,
const sp<SurfaceFlinger>& flinger);
virtual ~MonitoredProducer();
@@ -45,13 +45,14 @@
QueueBufferOutput* output);
virtual void cancelBuffer(int slot, const sp<Fence>& fence);
virtual int query(int what, int* value);
- virtual status_t connect(const sp<IBinder>& token, int api,
+ virtual status_t connect(const sp<IProducerListener>& token, int api,
bool producerControlledByApp, QueueBufferOutput* output);
virtual status_t disconnect(int api);
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
+ virtual IBinder* onAsBinder();
private:
- sp<BnGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferProducer> mProducer;
sp<SurfaceFlinger> mFlinger;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d084bf5..a346520 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -574,6 +574,18 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::clearAnimationFrameStats() {
+ Mutex::Autolock _l(mStateLock);
+ mAnimFrameTracker.clearStats();
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
+ Mutex::Autolock _l(mStateLock);
+ mAnimFrameTracker.getStats(outStats);
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
@@ -2255,14 +2267,14 @@
result.appendFormat("%" PRId64 "\n", period);
if (name.isEmpty()) {
- mAnimFrameTracker.dump(result);
+ mAnimFrameTracker.dumpStats(result);
} else {
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
if (name == layer->getName()) {
- layer->dumpStats(result);
+ layer->dumpFrameStats(result);
}
}
}
@@ -2282,11 +2294,11 @@
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
if (name.isEmpty() || (name == layer->getName())) {
- layer->clearStats();
+ layer->clearFrameStats();
}
}
- mAnimFrameTracker.clear();
+ mAnimFrameTracker.clearStats();
}
// This should only be called from the main thread. Otherwise it would need
@@ -2500,6 +2512,8 @@
case BOOT_FINISHED:
case BLANK:
case UNBLANK:
+ case CLEAR_ANIMATION_FRAME_STATS:
+ case GET_ANIMATION_FRAME_STATS:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 630f4b7..717ee66 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -210,6 +210,8 @@
// called when screen is turning back on
virtual void unblank(const sp<IBinder>& display);
virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info);
+ virtual status_t clearAnimationFrameStats();
+ virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
/* ------------------------------------------------------------------------
* DeathRecipient interface