Merge "Add "android.software.preview_sdk" feature" into oc-dev
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 5c04f6c..dfc3e58 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -25,7 +25,6 @@
namespace android {
GLHelper::GLHelper() :
- mGraphicBufferAlloc(new GraphicBufferAlloc()),
mDisplay(EGL_NO_DISPLAY),
mContext(EGL_NO_CONTEXT),
mDummySurface(EGL_NO_SURFACE),
@@ -203,7 +202,7 @@
sp<GLConsumer>* glConsumer, EGLSurface* surface) {
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer, mGraphicBufferAlloc);
+ BufferQueue::createBufferQueue(&producer, &consumer);
sp<GLConsumer> glc = new GLConsumer(consumer, name,
GL_TEXTURE_EXTERNAL_OES, false, true);
glc->setDefaultBufferSize(w, h);
diff --git a/cmds/flatland/GLHelper.h b/cmds/flatland/GLHelper.h
index 7a9e9e3..d09463a 100644
--- a/cmds/flatland/GLHelper.h
+++ b/cmds/flatland/GLHelper.h
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <gui/GraphicBufferAlloc.h>
#include <gui/GLConsumer.h>
#include <gui/Surface.h>
#include <gui/SurfaceControl.h>
@@ -75,8 +74,6 @@
bool setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders);
- sp<GraphicBufferAlloc> mGraphicBufferAlloc;
-
EGLDisplay mDisplay;
EGLContext mContext;
EGLSurface mDummySurface;
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index c47b0c8..ec1e543 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -16,7 +16,6 @@
#define ATRACE_TAG ATRACE_TAG_ALWAYS
-#include <gui/GraphicBufferAlloc.h>
#include <gui/Surface.h>
#include <gui/SurfaceControl.h>
#include <gui/GLConsumer.h>
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 4c57361..33bc43c 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -296,7 +296,7 @@
continue;
}
- vintf::ManifestHal *hal = manifest.getHal(fqName.package());
+ vintf::ManifestHal *hal = manifest.getAnyHal(fqName.package());
if (hal == nullptr) {
if (!manifest.add(vintf::ManifestHal{
.format = vintf::HalFormat::HIDL,
@@ -306,7 +306,7 @@
mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
continue;
}
- hal = manifest.getHal(fqName.package());
+ hal = manifest.getAnyHal(fqName.package());
}
if (hal == nullptr) {
mErr << "Warning: cannot get hal '" << fqInstanceName
diff --git a/include/binder b/include/binder
new file mode 120000
index 0000000..35a022a
--- /dev/null
+++ b/include/binder
@@ -0,0 +1 @@
+../libs/binder/include/binder/
\ No newline at end of file
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index c95c535..bd62d85 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -23,10 +23,6 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/IConsumerListener.h>
-// These are only required to keep other parts of the framework with incomplete
-// dependencies building successfully
-#include <gui/IGraphicBufferAlloc.h>
-
namespace android {
class BufferQueue {
@@ -81,11 +77,9 @@
// needed gralloc buffers.
static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
- const sp<IGraphicBufferAlloc>& allocator = NULL,
bool consumerIsSurfaceFlinger = false);
-private:
- BufferQueue(); // Create through createBufferQueue
+ BufferQueue() = delete; // Create through createBufferQueue
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index da574ec..1e22d28 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -110,7 +110,7 @@
virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
// setConsumerName sets the name used in logging
- virtual void setConsumerName(const String8& name);
+ status_t setConsumerName(const String8& name) override;
// setDefaultBufferFormat allows the BufferQueue to create
// GraphicBuffers of a defaultFormat if no format is specified
@@ -135,7 +135,7 @@
virtual status_t setTransformHint(uint32_t hint);
// Retrieve the sideband buffer stream, if any.
- virtual sp<NativeHandle> getSidebandStream() const;
+ status_t getSidebandStream(sp<NativeHandle>* outStream) const override;
// See IGraphicBufferConsumer::getOccupancyHistory
virtual status_t getOccupancyHistory(bool forceFlush,
@@ -145,7 +145,7 @@
virtual status_t discardFreeBuffers() override;
// dump our state in a String
- virtual void dumpState(String8& result, const char* prefix) const;
+ status_t dumpState(const String8& prefix, String8* outResult) const override;
// Functions required for backwards compatibility.
// These will be modified/renamed in IGraphicBufferConsumer and will be
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index b1c730a..cfe716f 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -51,7 +51,6 @@
namespace android {
class IConsumerListener;
-class IGraphicBufferAlloc;
class IProducerListener;
class BufferQueueCore : public virtual RefBase {
@@ -79,14 +78,13 @@
typedef Vector<BufferItem> Fifo;
// BufferQueueCore manages a pool of gralloc memory slots to be used by
- // producers and consumers. allocator is used to allocate all the needed
- // gralloc buffers.
- BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator = NULL);
+ // producers and consumers.
+ BufferQueueCore();
virtual ~BufferQueueCore();
private:
// Dump our state in a string
- void dumpState(String8& result, const char* prefix) const;
+ void dumpState(const String8& prefix, String8* outResult) const;
// getMinUndequeuedBufferCountLocked returns the minimum number of buffers
// that must remain in a state other than DEQUEUED. The async parameter
@@ -143,10 +141,6 @@
void validateConsistencyLocked() const;
#endif
- // mAllocator is the connection to SurfaceFlinger that is used to allocate
- // new GraphicBuffer objects.
- sp<IGraphicBufferAlloc> mAllocator;
-
// mMutex is the mutex used to prevent concurrent access to the member
// variables of BufferQueueCore objects. It must be locked whenever any
// member variable is accessed.
diff --git a/include/gui/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h
deleted file mode 100644
index 54c9829..0000000
--- a/include/gui/GraphicBufferAlloc.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2012 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_GRAPHIC_BUFFER_ALLOC_H
-#define ANDROID_GUI_GRAPHIC_BUFFER_ALLOC_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <gui/IGraphicBufferAlloc.h>
-#include <ui/PixelFormat.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-class GraphicBuffer;
-
-/*
- * Concrete implementation of the IGraphicBufferAlloc interface.
- *
- * This can create GraphicBuffer instance across processes. This is mainly used
- * by surfaceflinger.
- */
-
-class GraphicBufferAlloc : public BnGraphicBufferAlloc {
-public:
- GraphicBufferAlloc();
- virtual ~GraphicBufferAlloc();
- virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
- uint32_t height, PixelFormat format, uint32_t layerCount,
- uint64_t producerUsage, uint64_t consumerUsage,
- std::string requestorName, status_t* error) override;
-};
-
-
-} // namespace android
-
-#endif // ANDROID_GUI_GRAPHIC_BUFFER_ALLOC_H
diff --git a/include/gui/IGraphicBufferAlloc.h b/include/gui/IGraphicBufferAlloc.h
deleted file mode 100644
index 1e578cc..0000000
--- a/include/gui/IGraphicBufferAlloc.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2011 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_IGRAPHIC_BUFFER_ALLOC_H
-#define ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/IInterface.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-#include <utils/RefBase.h>
-
-#include <string>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-class IGraphicBufferAlloc : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(GraphicBufferAlloc)
-
- /* Create a new GraphicBuffer for the client to use.
- */
- virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
- uint64_t consumerUsage, std::string requestorName,
- status_t* error) = 0;
-
- sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t layerCount, uint32_t usage,
- status_t* error) {
- return createGraphicBuffer(w, h, format, layerCount, usage,
- usage, "<Unknown>", error);
- }
-
- sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t layerCount, uint32_t usage,
- std::string requestorName, status_t* error) {
- return createGraphicBuffer(w, h, format, layerCount, usage,
- usage, requestorName, error);
- }
-
- sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
- uint64_t consumerUsage, status_t* error) {
- return createGraphicBuffer(w, h, format, layerCount, producerUsage,
- consumerUsage, "<Unknown>", error);
- }
-};
-
-// ----------------------------------------------------------------------------
-
-class BnGraphicBufferAlloc : public BnInterface<IGraphicBufferAlloc>
-{
-public:
- virtual status_t onTransact(uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 60b7d24..63254ed 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -14,27 +14,21 @@
* limitations under the License.
*/
-#ifndef ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H
-#define ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-
-#include <binder/IInterface.h>
-
-#include <ui/PixelFormat.h>
+#pragma once
#include <gui/OccupancyTracker.h>
+#include <binder/IInterface.h>
+#include <binder/SafeInterface.h>
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <ui/PixelFormat.h>
+
+#include <utils/Errors.h>
+
namespace android {
-// ----------------------------------------------------------------------------
class BufferItem;
class Fence;
@@ -43,11 +37,12 @@
class NativeHandle;
class IGraphicBufferConsumer : public IInterface {
-
public:
+ DECLARE_META_INTERFACE(GraphicBufferConsumer)
+
enum {
- // Returned by releaseBuffer, after which the consumer must
- // free any references to the just-released buffer that it might have.
+ // Returned by releaseBuffer, after which the consumer must free any references to the
+ // just-released buffer that it might have.
STALE_BUFFER_SLOT = 1,
// Returned by dequeueBuffer if there are no pending buffers available.
NO_BUFFER_AVAILABLE,
@@ -55,88 +50,79 @@
PRESENT_LATER,
};
- // acquireBuffer attempts to acquire ownership of the next pending buffer in
- // the BufferQueue. If no buffer is pending then it returns
- // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the
- // information about the buffer is returned in BufferItem.
+ // acquireBuffer attempts to acquire ownership of the next pending buffer in the BufferQueue.
+ // If no buffer is pending then it returns NO_BUFFER_AVAILABLE. If a buffer is successfully
+ // acquired, the information about the buffer is returned in BufferItem.
//
- // If the buffer returned had previously been
- // acquired then the BufferItem::mGraphicBuffer field of buffer is set to
- // NULL and it is assumed that the consumer still holds a reference to the
+ // If the buffer returned had previously been acquired then the BufferItem::mGraphicBuffer field
+ // of buffer is set to NULL and it is assumed that the consumer still holds a reference to the
// buffer.
//
- // If presentWhen is non-zero, it indicates the time when the buffer will
- // be displayed on screen. If the buffer's timestamp is farther in the
- // future, the buffer won't be acquired, and PRESENT_LATER will be
- // returned. The presentation time is in nanoseconds, and the time base
+ // If presentWhen is non-zero, it indicates the time when the buffer will be displayed on
+ // screen. If the buffer's timestamp is farther in the future, the buffer won't be acquired, and
+ // PRESENT_LATER will be returned. The presentation time is in nanoseconds, and the time base
// is CLOCK_MONOTONIC.
//
- // If maxFrameNumber is non-zero, it indicates that acquireBuffer should
- // only return a buffer with a frame number less than or equal to
- // maxFrameNumber. If no such frame is available (such as when a buffer has
- // been replaced but the consumer has not received the onFrameReplaced
- // callback), then PRESENT_LATER will be returned.
+ // If maxFrameNumber is non-zero, it indicates that acquireBuffer should only return a buffer
+ // with a frame number less than or equal to maxFrameNumber. If no such frame is available
+ // (such as when a buffer has been replaced but the consumer has not received the
+ // onFrameReplaced callback), then PRESENT_LATER will be returned.
//
// Return of NO_ERROR means the operation completed as normal.
//
- // Return of a positive value means the operation could not be completed
- // at this time, but the user should try again later:
+ // Return of a positive value means the operation could not be completed at this time, but the
+ // user should try again later:
// * NO_BUFFER_AVAILABLE - no buffer is pending (nothing queued by producer)
// * PRESENT_LATER - the buffer's timestamp is farther in the future
//
// Return of a negative value means an error has occurred:
// * INVALID_OPERATION - too many buffers have been acquired
virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
- uint64_t maxFrameNumber = 0) = 0;
+ uint64_t maxFrameNumber = 0) = 0;
- // detachBuffer attempts to remove all ownership of the buffer in the given
- // slot from the buffer queue. If this call succeeds, the slot will be
- // freed, and there will be no way to obtain the buffer from this interface.
- // The freed slot will remain unallocated until either it is selected to
- // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached
- // to the slot. The buffer must have already been acquired.
+ // detachBuffer attempts to remove all ownership of the buffer in the given slot from the buffer
+ // queue. If this call succeeds, the slot will be freed, and there will be no way to obtain the
+ // buffer from this interface. The freed slot will remain unallocated until either it is
+ // selected to hold a freshly allocated buffer in dequeueBuffer or a buffer is attached to the
+ // slot. The buffer must have already been acquired.
//
// Return of a value other than NO_ERROR means an error has occurred:
- // * BAD_VALUE - the given slot number is invalid, either because it is
- // out of the range [0, NUM_BUFFER_SLOTS) or because the slot
- // it refers to is not currently acquired.
+ // * BAD_VALUE - the given slot number is invalid, either because it is out of the range
+ // [0, NUM_BUFFER_SLOTS) or because the slot it refers to is not
+ // currently acquired.
virtual status_t detachBuffer(int slot) = 0;
- // attachBuffer attempts to transfer ownership of a buffer to the buffer
- // queue. If this call succeeds, it will be as if this buffer was acquired
- // from the returned slot number. As such, this call will fail if attaching
- // this buffer would cause too many buffers to be simultaneously acquired.
+ // attachBuffer attempts to transfer ownership of a buffer to the BufferQueue. If this call
+ // succeeds, it will be as if this buffer was acquired from the returned slot number. As such,
+ // this call will fail if attaching this buffer would cause too many buffers to be
+ // simultaneously acquired.
//
- // If the buffer is successfully attached, its frameNumber is initialized
- // to 0. This must be passed into the releaseBuffer call or else the buffer
- // will be deallocated as stale.
+ // If the buffer is successfully attached, its frameNumber is initialized to 0. This must be
+ // passed into the releaseBuffer call or else the buffer will be deallocated as stale.
//
// Return of a value other than NO_ERROR means an error has occurred:
- // * BAD_VALUE - outSlot or buffer were NULL, or the generation number of
- // the buffer did not match the buffer queue.
- // * INVALID_OPERATION - cannot attach the buffer because it would cause too
- // many buffers to be acquired.
+ // * BAD_VALUE - outSlot or buffer were NULL, or the generation number of the buffer did not
+ // match the BufferQueue.
+ // * INVALID_OPERATION - cannot attach the buffer because it would cause too many buffers
+ // to be acquired.
// * NO_MEMORY - no free slots available
- virtual status_t attachBuffer(int *outSlot,
- const sp<GraphicBuffer>& buffer) = 0;
+ virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) = 0;
- // releaseBuffer releases a buffer slot from the consumer back to the
- // BufferQueue. This may be done while the buffer's contents are still
- // being accessed. The fence will signal when the buffer is no longer
- // in use. frameNumber is used to indentify the exact buffer returned.
+ // releaseBuffer releases a buffer slot from the consumer back to the BufferQueue. This may be
+ // done while the buffer's contents are still being accessed. The fence will signal when the
+ // buffer is no longer in use. frameNumber is used to identify the exact buffer returned.
//
- // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
- // any references to the just-released buffer that it might have, as if it
- // had received a onBuffersReleased() call with a mask set for the released
- // buffer.
+ // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free any references to the
+ // just-released buffer that it might have, as if it had received a onBuffersReleased() call
+ // with a mask set for the released buffer.
//
- // Note that the dependencies on EGL will be removed once we switch to using
- // the Android HW Sync HAL.
+ // Note that the dependencies on EGL will be removed once we switch to using the Android HW
+ // Sync HAL.
//
// Return of NO_ERROR means the operation completed as normal.
//
- // Return of a positive value means the operation could not be completed
- // at this time, but the user should try again later:
+ // Return of a positive value means the operation could not be completed at this time, but the
+ // user should try again later:
// * STALE_BUFFER_SLOT - see above (second paragraph)
//
// Return of a negative value means an error has occurred:
@@ -144,159 +130,157 @@
// * the buffer slot was invalid
// * the fence was NULL
// * the buffer slot specified is not in the acquired state
- virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
- EGLDisplay display, EGLSyncKHR fence,
- const sp<Fence>& releaseFence) = 0;
+ virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display,
+ EGLSyncKHR fence, const sp<Fence>& releaseFence) = 0;
- // consumerConnect connects a consumer to the BufferQueue. Only one
- // consumer may be connected, and when that consumer disconnects the
- // BufferQueue is placed into the "abandoned" state, causing most
- // interactions with the BufferQueue by the producer to fail.
- // controlledByApp indicates whether the consumer is controlled by
- // the application.
+ status_t releaseHelper(int buf, uint64_t frameNumber, const sp<Fence>& releaseFence) {
+ return releaseBuffer(buf, frameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
+ }
+ // This is explicitly *not* the actual signature of IGBC::releaseBuffer, but:
+ // 1) We have no easy way to send the EGL objects across Binder
+ // 2) This has always been broken, probably because
+ // 3) IGBC is rarely remoted
+ // For now, we will choose to bury our heads in the sand and ignore this problem until such time
+ // as we can finally finish converting away from EGL sync to native Android sync
+ using ReleaseBuffer = decltype(&IGraphicBufferConsumer::releaseHelper);
+
+ // consumerConnect connects a consumer to the BufferQueue. Only one consumer may be connected,
+ // and when that consumer disconnects the BufferQueue is placed into the "abandoned" state,
+ // causing most interactions with the BufferQueue by the producer to fail. controlledByApp
+ // indicates whether the consumer is controlled by the application.
//
// consumer may not be NULL.
//
// Return of a value other than NO_ERROR means an error has occurred:
- // * NO_INIT - the buffer queue has been abandoned
+ // * NO_INIT - the BufferQueue has been abandoned
// * BAD_VALUE - a NULL consumer was provided
- virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) = 0;
+ virtual status_t consumerConnect(const sp<IConsumerListener>& consumer,
+ bool controlledByApp) = 0;
- // consumerDisconnect disconnects a consumer from the BufferQueue. All
- // buffers will be freed and the BufferQueue is placed in the "abandoned"
- // state, causing most interactions with the BufferQueue by the producer to
- // fail.
+ // consumerDisconnect disconnects a consumer from the BufferQueue. All buffers will be freed and
+ // the BufferQueue is placed in the "abandoned" state, causing most interactions with the
+ // BufferQueue by the producer to fail.
//
// Return of a value other than NO_ERROR means an error has occurred:
// * BAD_VALUE - no consumer is currently connected
virtual status_t consumerDisconnect() = 0;
- // getReleasedBuffers sets the value pointed to by slotMask to a bit set.
- // Each bit index with a 1 corresponds to a released buffer slot with that
- // index value. In particular, a released buffer is one that has
- // been released by the BufferQueue but have not yet been released by the consumer.
+ // getReleasedBuffers sets the value pointed to by slotMask to a bit set. Each bit index with a
+ // 1 corresponds to a released buffer slot with that index value. In particular, a released
+ // buffer is one that has been released by the BufferQueue but has not yet been released by
+ // the consumer.
//
// This should be called from the onBuffersReleased() callback.
//
// Return of a value other than NO_ERROR means an error has occurred:
- // * NO_INIT - the buffer queue has been abandoned.
+ // * NO_INIT - the BufferQueue has been abandoned.
virtual status_t getReleasedBuffers(uint64_t* slotMask) = 0;
- // setDefaultBufferSize is used to set the size of buffers returned by
- // dequeueBuffer when a width and height of zero is requested. Default
- // is 1x1.
+ // setDefaultBufferSize is used to set the size of buffers returned by dequeueBuffer when a
+ // width and height of zero is requested. Default is 1x1.
//
// Return of a value other than NO_ERROR means an error has occurred:
// * BAD_VALUE - either w or h was zero
virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0;
- // setMaxBufferCount sets the maximum value for the number of buffers used
- // in the buffer queue (the initial default is NUM_BUFFER_SLOTS). If a call
- // to setMaxAcquiredBufferCount (by the consumer), or a call to setAsyncMode
- // or setMaxDequeuedBufferCount (by the producer), would cause this value to
- // be exceeded then that call will fail. This call will fail if a producer
+ // setMaxBufferCount sets the maximum value for the number of buffers used in the BufferQueue
+ // (the initial default is NUM_BUFFER_SLOTS). If a call to setMaxAcquiredBufferCount (by the
+ // consumer), or a call to setAsyncMode or setMaxDequeuedBufferCount (by the producer), would
+ // cause this value to be exceeded then that call will fail. This call will fail if a producer
// is connected to the BufferQueue.
//
- // The count must be between 1 and NUM_BUFFER_SLOTS, inclusive. The count
- // cannot be less than maxAcquiredBufferCount.
+ // The count must be between 1 and NUM_BUFFER_SLOTS, inclusive. The count cannot be less than
+ // maxAcquiredBufferCount.
//
// Return of a value other than NO_ERROR means an error has occurred:
// * BAD_VALUE - one of the below conditions occurred:
- // * bufferCount was out of range (see above).
- // * failure to adjust the number of available slots.
+ // * bufferCount was out of range (see above).
+ // * failure to adjust the number of available slots.
// * INVALID_OPERATION - attempting to call this after a producer connected.
virtual status_t setMaxBufferCount(int bufferCount) = 0;
- // setMaxAcquiredBufferCount sets the maximum number of buffers that can
- // be acquired by the consumer at one time (default 1). If this method
- // succeeds, any new buffer slots will be both unallocated and owned by the
- // BufferQueue object (i.e. they are not owned by the producer or consumer).
- // Calling this may also cause some buffer slots to be emptied.
+ // setMaxAcquiredBufferCount sets the maximum number of buffers that can be acquired by the
+ // consumer at one time (default 1). If this method succeeds, any new buffer slots will be both
+ // unallocated and owned by the BufferQueue object (i.e. they are not owned by the producer or
+ // consumer). Calling this may also cause some buffer slots to be emptied.
//
- // This function should not be called with a value of maxAcquiredBuffers
- // that is less than the number of currently acquired buffer slots. Doing so
- // will result in a BAD_VALUE error.
+ // This function should not be called with a value of maxAcquiredBuffers that is less than the
+ // number of currently acquired buffer slots. Doing so will result in a BAD_VALUE error.
//
- // maxAcquiredBuffers must be (inclusive) between 1 and
- // MAX_MAX_ACQUIRED_BUFFERS. It also cannot cause the maxBufferCount value
- // to be exceeded.
+ // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS. It also cannot
+ // cause the maxBufferCount value to be exceeded.
//
// Return of a value other than NO_ERROR means an error has occurred:
- // * NO_INIT - the buffer queue has been abandoned
+ // * NO_INIT - the BufferQueue has been abandoned
// * BAD_VALUE - one of the below conditions occurred:
- // * maxAcquiredBuffers was out of range (see above).
- // * failure to adjust the number of available slots.
- // * client would have more than the requested number of
- // acquired buffers after this call
+ // * maxAcquiredBuffers was out of range (see above).
+ // * failure to adjust the number of available slots.
+ // * client would have more than the requested number of acquired buffers after
+ // this call
// * INVALID_OPERATION - attempting to call this after a producer connected.
virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
// setConsumerName sets the name used in logging
- virtual void setConsumerName(const String8& name) = 0;
+ virtual status_t setConsumerName(const String8& name) = 0;
- // setDefaultBufferFormat allows the BufferQueue to create
- // GraphicBuffers of a defaultFormat if no format is specified
- // in dequeueBuffer.
- // The initial default is PIXEL_FORMAT_RGBA_8888.
+ // setDefaultBufferFormat allows the BufferQueue to create GraphicBuffers of a defaultFormat if
+ // no format is specified in dequeueBuffer. The initial default is PIXEL_FORMAT_RGBA_8888.
//
// Return of a value other than NO_ERROR means an unknown error has occurred.
virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) = 0;
- // setDefaultBufferDataSpace is a request to the producer to provide buffers
- // of the indicated dataSpace. The producer may ignore this request.
- // The initial default is HAL_DATASPACE_UNKNOWN.
+ // setDefaultBufferDataSpace is a request to the producer to provide buffers of the indicated
+ // dataSpace. The producer may ignore this request. The initial default is
+ // HAL_DATASPACE_UNKNOWN.
//
// Return of a value other than NO_ERROR means an unknown error has occurred.
- virtual status_t setDefaultBufferDataSpace(
- android_dataspace defaultDataSpace) = 0;
+ virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) = 0;
- // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
- // These are merged with the bits passed to dequeueBuffer. The values are
- // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
+ // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. These are merged
+ // with the bits passed to dequeueBuffer. The values are enumerated in gralloc.h,
+ // e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
//
// Return of a value other than NO_ERROR means an unknown error has occurred.
virtual status_t setConsumerUsageBits(uint32_t usage) = 0;
- // setTransformHint bakes in rotation to buffers so overlays can be used.
- // The values are enumerated in window.h, e.g.
- // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform).
+ // setTransformHint bakes in rotation to buffers so overlays can be used. The values are
+ // enumerated in window.h, e.g. NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0
+ // (no transform).
//
// Return of a value other than NO_ERROR means an unknown error has occurred.
virtual status_t setTransformHint(uint32_t hint) = 0;
// Retrieve the sideband buffer stream, if any.
- virtual sp<NativeHandle> getSidebandStream() const = 0;
+ virtual status_t getSidebandStream(sp<NativeHandle>* outStream) const = 0;
- // Retrieves any stored segments of the occupancy history of this
- // BufferQueue and clears them. Optionally closes out the pending segment if
- // forceFlush is true.
+ // Retrieves any stored segments of the occupancy history of this BufferQueue and clears them.
+ // Optionally closes out the pending segment if forceFlush is true.
virtual status_t getOccupancyHistory(bool forceFlush,
- std::vector<OccupancyTracker::Segment>* outHistory) = 0;
+ std::vector<OccupancyTracker::Segment>* outHistory) = 0;
- // discardFreeBuffers releases all currently-free buffers held by the queue,
- // in order to reduce the memory consumption of the queue to the minimum
- // possible without discarding data.
+ // discardFreeBuffers releases all currently-free buffers held by the BufferQueue, in order to
+ // reduce the memory consumption of the BufferQueue to the minimum possible without
+ // discarding data.
virtual status_t discardFreeBuffers() = 0;
// dump state into a string
- virtual void dumpState(String8& result, const char* prefix) const = 0;
+ virtual status_t dumpState(const String8& prefix, String8* outResult) const = 0;
-public:
- DECLARE_META_INTERFACE(GraphicBufferConsumer)
+ // Provide backwards source compatibility
+ void dumpState(String8& result, const char* prefix) {
+ String8 returned;
+ dumpState(String8(prefix), &returned);
+ result.append(returned);
+ }
};
-// ----------------------------------------------------------------------------
-
-class BnGraphicBufferConsumer : public BnInterface<IGraphicBufferConsumer>
-{
+class BnGraphicBufferConsumer : public SafeBnInterface<IGraphicBufferConsumer> {
public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
+ BnGraphicBufferConsumer()
+ : SafeBnInterface<IGraphicBufferConsumer>("BnGraphicBufferConsumer") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) override;
};
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H
+} // namespace android
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 9870ba0..1112973 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -41,7 +41,6 @@
struct DisplayStatInfo;
class HdrCapabilities;
class IDisplayEventConnection;
-class IGraphicBufferAlloc;
class IGraphicBufferProducer;
class ISurfaceComposerClient;
class Rect;
@@ -89,10 +88,6 @@
virtual sp<ISurfaceComposerClient> createScopedConnection(
const sp<IGraphicBufferProducer>& parent) = 0;
- /* create a graphic buffer allocator
- */
- virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;
-
/* return an IDisplayEventConnection */
virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0;
@@ -205,7 +200,7 @@
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
- CREATE_GRAPHIC_BUFFER_ALLOC,
+ UNUSED, // formerly CREATE_GRAPHIC_BUFFER_ALLOC
CREATE_DISPLAY_EVENT_CONNECTION,
CREATE_DISPLAY,
DESTROY_DISPLAY,
diff --git a/include/private/binder b/include/private/binder
new file mode 120000
index 0000000..09e9076
--- /dev/null
+++ b/include/private/binder
@@ -0,0 +1 @@
+../../libs/binder/include/private/binder
\ No newline at end of file
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b225128..204fdb5 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -12,9 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+cc_library_headers {
+ name: "libbinder_headers",
+ export_include_dirs: ["include"],
+}
+
cc_library {
name: "libbinder",
+ // for vndbinder
+ vendor_available: true,
+
srcs: [
"AppOpsManager.cpp",
"Binder.cpp",
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 9ccf07c..add5e74 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -79,6 +79,11 @@
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
+ // Allow for initWithDriver to be called repeatedly with the same
+ // driver.
+ if (!strcmp(gProcess->getDriverName().c_str(), driver)) {
+ return gProcess;
+ }
LOG_ALWAYS_FATAL("ProcessState was already initialized.");
}
gProcess = new ProcessState(driver);
diff --git a/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
similarity index 100%
rename from include/binder/AppOpsManager.h
rename to libs/binder/include/binder/AppOpsManager.h
diff --git a/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
similarity index 100%
rename from include/binder/Binder.h
rename to libs/binder/include/binder/Binder.h
diff --git a/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h
similarity index 100%
rename from include/binder/BinderService.h
rename to libs/binder/include/binder/BinderService.h
diff --git a/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
similarity index 100%
rename from include/binder/BpBinder.h
rename to libs/binder/include/binder/BpBinder.h
diff --git a/include/binder/BufferedTextOutput.h b/libs/binder/include/binder/BufferedTextOutput.h
similarity index 100%
rename from include/binder/BufferedTextOutput.h
rename to libs/binder/include/binder/BufferedTextOutput.h
diff --git a/include/binder/Debug.h b/libs/binder/include/binder/Debug.h
similarity index 100%
rename from include/binder/Debug.h
rename to libs/binder/include/binder/Debug.h
diff --git a/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
similarity index 100%
rename from include/binder/IActivityManager.h
rename to libs/binder/include/binder/IActivityManager.h
diff --git a/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h
similarity index 100%
rename from include/binder/IAppOpsCallback.h
rename to libs/binder/include/binder/IAppOpsCallback.h
diff --git a/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
similarity index 100%
rename from include/binder/IAppOpsService.h
rename to libs/binder/include/binder/IAppOpsService.h
diff --git a/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h
similarity index 100%
rename from include/binder/IBatteryStats.h
rename to libs/binder/include/binder/IBatteryStats.h
diff --git a/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
similarity index 100%
rename from include/binder/IBinder.h
rename to libs/binder/include/binder/IBinder.h
diff --git a/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
similarity index 100%
rename from include/binder/IInterface.h
rename to libs/binder/include/binder/IInterface.h
diff --git a/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h
similarity index 100%
rename from include/binder/IMediaResourceMonitor.h
rename to libs/binder/include/binder/IMediaResourceMonitor.h
diff --git a/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h
similarity index 100%
rename from include/binder/IMemory.h
rename to libs/binder/include/binder/IMemory.h
diff --git a/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
similarity index 100%
rename from include/binder/IPCThreadState.h
rename to libs/binder/include/binder/IPCThreadState.h
diff --git a/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
similarity index 100%
rename from include/binder/IPermissionController.h
rename to libs/binder/include/binder/IPermissionController.h
diff --git a/include/binder/IProcessInfoService.h b/libs/binder/include/binder/IProcessInfoService.h
similarity index 100%
rename from include/binder/IProcessInfoService.h
rename to libs/binder/include/binder/IProcessInfoService.h
diff --git a/include/binder/IResultReceiver.h b/libs/binder/include/binder/IResultReceiver.h
similarity index 100%
rename from include/binder/IResultReceiver.h
rename to libs/binder/include/binder/IResultReceiver.h
diff --git a/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
similarity index 100%
rename from include/binder/IServiceManager.h
rename to libs/binder/include/binder/IServiceManager.h
diff --git a/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
similarity index 100%
rename from include/binder/IShellCallback.h
rename to libs/binder/include/binder/IShellCallback.h
diff --git a/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h
similarity index 100%
rename from include/binder/IpPrefix.h
rename to libs/binder/include/binder/IpPrefix.h
diff --git a/include/binder/Map.h b/libs/binder/include/binder/Map.h
similarity index 100%
rename from include/binder/Map.h
rename to libs/binder/include/binder/Map.h
diff --git a/include/binder/MemoryBase.h b/libs/binder/include/binder/MemoryBase.h
similarity index 100%
rename from include/binder/MemoryBase.h
rename to libs/binder/include/binder/MemoryBase.h
diff --git a/include/binder/MemoryDealer.h b/libs/binder/include/binder/MemoryDealer.h
similarity index 100%
rename from include/binder/MemoryDealer.h
rename to libs/binder/include/binder/MemoryDealer.h
diff --git a/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
similarity index 100%
rename from include/binder/MemoryHeapBase.h
rename to libs/binder/include/binder/MemoryHeapBase.h
diff --git a/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
similarity index 100%
rename from include/binder/Parcel.h
rename to libs/binder/include/binder/Parcel.h
diff --git a/include/binder/Parcelable.h b/libs/binder/include/binder/Parcelable.h
similarity index 100%
rename from include/binder/Parcelable.h
rename to libs/binder/include/binder/Parcelable.h
diff --git a/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h
similarity index 100%
rename from include/binder/PermissionCache.h
rename to libs/binder/include/binder/PermissionCache.h
diff --git a/include/binder/PersistableBundle.h b/libs/binder/include/binder/PersistableBundle.h
similarity index 100%
rename from include/binder/PersistableBundle.h
rename to libs/binder/include/binder/PersistableBundle.h
diff --git a/include/binder/ProcessInfoService.h b/libs/binder/include/binder/ProcessInfoService.h
similarity index 100%
rename from include/binder/ProcessInfoService.h
rename to libs/binder/include/binder/ProcessInfoService.h
diff --git a/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
similarity index 100%
rename from include/binder/ProcessState.h
rename to libs/binder/include/binder/ProcessState.h
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h
index 44c1352..3bfd462 100644
--- a/libs/binder/include/binder/SafeInterface.h
+++ b/libs/binder/include/binder/SafeInterface.h
@@ -26,6 +26,8 @@
#include <utils/CallStack.h>
#endif
+#include <utils/NativeHandle.h>
+
#include <functional>
#include <type_traits>
@@ -44,6 +46,19 @@
status_t write(Parcel* parcel, bool b) const {
return callParcel("writeBool", [&]() { return parcel->writeBool(b); });
}
+ template <typename E>
+ typename std::enable_if<std::is_enum<E>::value, status_t>::type read(const Parcel& parcel,
+ E* e) const {
+ typename std::underlying_type<E>::type u{};
+ status_t result = read(parcel, &u);
+ *e = static_cast<E>(u);
+ return result;
+ }
+ template <typename E>
+ typename std::enable_if<std::is_enum<E>::value, status_t>::type write(Parcel* parcel,
+ E e) const {
+ return write(parcel, static_cast<typename std::underlying_type<E>::type>(e));
+ }
template <typename T>
typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type read(
const Parcel& parcel, T* t) const {
@@ -55,6 +70,17 @@
return callParcel("write(Flattenable)", [&]() { return parcel->write(t); });
}
template <typename T>
+ typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type read(
+ const Parcel& parcel, sp<T>* t) const {
+ *t = new T{};
+ return callParcel("read(sp<Flattenable>)", [&]() { return parcel.read(*(t->get())); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type write(
+ Parcel* parcel, const sp<T>& t) const {
+ return callParcel("write(sp<Flattenable>)", [&]() { return parcel->write(*(t.get())); });
+ }
+ template <typename T>
typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type read(
const Parcel& parcel, T* t) const {
return callParcel("read(LightFlattenable)", [&]() { return parcel.read(*t); });
@@ -64,6 +90,18 @@
Parcel* parcel, const T& t) const {
return callParcel("write(LightFlattenable)", [&]() { return parcel->write(t); });
}
+ template <typename NH>
+ typename std::enable_if<std::is_same<NH, sp<NativeHandle>>::value, status_t>::type read(
+ const Parcel& parcel, NH* nh) {
+ *nh = NativeHandle::create(parcel.readNativeHandle(), true);
+ return NO_ERROR;
+ }
+ template <typename NH>
+ typename std::enable_if<std::is_same<NH, sp<NativeHandle>>::value, status_t>::type write(
+ Parcel* parcel, const NH& nh) {
+ return callParcel("write(sp<NativeHandle>)",
+ [&]() { return parcel->writeNativeHandle(nh->handle()); });
+ }
template <typename T>
typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read(
const Parcel& parcel, T* t) const {
@@ -81,7 +119,8 @@
return callParcel("writeString8", [&]() { return parcel->writeString8(str); });
}
template <typename T>
- status_t read(const Parcel& parcel, sp<T>* pointer) const {
+ typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type read(
+ const Parcel& parcel, sp<T>* pointer) const {
return callParcel("readNullableStrongBinder",
[&]() { return parcel.readNullableStrongBinder(pointer); });
}
@@ -92,10 +131,27 @@
[&]() { return parcel->writeStrongBinder(pointer); });
}
template <typename T>
+ typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type read(
+ const Parcel& parcel, sp<T>* pointer) const {
+ return callParcel("readNullableStrongBinder[IInterface]",
+ [&]() { return parcel.readNullableStrongBinder(pointer); });
+ }
+ template <typename T>
typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type write(
Parcel* parcel, const sp<T>& interface) const {
return write(parcel, IInterface::asBinder(interface));
}
+ template <typename T>
+ typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read(
+ const Parcel& parcel, std::vector<T>* v) const {
+ return callParcel("readParcelableVector", [&]() { return parcel.readParcelableVector(v); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type write(
+ Parcel* parcel, const std::vector<T>& v) const {
+ return callParcel("writeParcelableVector",
+ [&]() { return parcel->writeParcelableVector(v); });
+ }
// Templates to handle integral types. We use a struct template to require that the called
// function exactly matches the signedness and size of the argument (e.g., the argument isn't
@@ -121,6 +177,24 @@
}
};
template <typename I>
+ struct HandleInt<true, 8, I> {
+ static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+ return handler.callParcel("readInt64", [&]() { return parcel.readInt64(i); });
+ }
+ static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+ return handler.callParcel("writeInt64", [&]() { return parcel->writeInt64(i); });
+ }
+ };
+ template <typename I>
+ struct HandleInt<false, 8, I> {
+ static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+ return handler.callParcel("readUint64", [&]() { return parcel.readUint64(i); });
+ }
+ static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+ return handler.callParcel("writeUint64", [&]() { return parcel->writeUint64(i); });
+ }
+ };
+ template <typename I>
typename std::enable_if<std::is_integral<I>::value, status_t>::type read(const Parcel& parcel,
I* i) const {
return HandleInt<std::is_signed<I>::value, sizeof(I), I>::read(*this, parcel, i);
diff --git a/include/binder/Status.h b/libs/binder/include/binder/Status.h
similarity index 100%
rename from include/binder/Status.h
rename to libs/binder/include/binder/Status.h
diff --git a/include/binder/TextOutput.h b/libs/binder/include/binder/TextOutput.h
similarity index 100%
rename from include/binder/TextOutput.h
rename to libs/binder/include/binder/TextOutput.h
diff --git a/include/binder/Value.h b/libs/binder/include/binder/Value.h
similarity index 100%
rename from include/binder/Value.h
rename to libs/binder/include/binder/Value.h
diff --git a/include/private/binder/ParcelValTypes.h b/libs/binder/include/private/binder/ParcelValTypes.h
similarity index 100%
rename from include/private/binder/ParcelValTypes.h
rename to libs/binder/include/private/binder/ParcelValTypes.h
diff --git a/include/private/binder/Static.h b/libs/binder/include/private/binder/Static.h
similarity index 100%
rename from include/private/binder/Static.h
rename to libs/binder/include/private/binder/Static.h
diff --git a/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
similarity index 100%
rename from include/private/binder/binder_module.h
rename to libs/binder/include/private/binder/binder_module.h
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 1ee4b6f..853ca16 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -100,6 +100,7 @@
shared_libs: [
"libbinder",
+ "libcutils",
"liblog",
"libutils",
],
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index d1f63a7..6a16e24 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -28,13 +28,26 @@
#include <gtest/gtest.h>
#pragma clang diagnostic pop
+#include <utils/LightRefBase.h>
+#include <utils/NativeHandle.h>
+
+#include <cutils/native_handle.h>
+
#include <optional>
+#include <sys/eventfd.h>
+
using namespace std::chrono_literals; // NOLINT - google-build-using-namespace
namespace android {
namespace tests {
+enum class TestEnum : uint32_t {
+ INVALID = 0,
+ INITIAL = 1,
+ FINAL = 2,
+};
+
// This class serves two purposes:
// 1) It ensures that the implementation doesn't require copying or moving the data (for
// efficiency purposes)
@@ -90,6 +103,48 @@
int32_t value = 0;
};
+// It seems like this should be able to inherit from TestFlattenable (to avoid duplicating code),
+// but the SafeInterface logic can't easily be extended to find an indirect Flattenable<T>
+// base class
+class TestLightRefBaseFlattenable : public Flattenable<TestLightRefBaseFlattenable>,
+ public LightRefBase<TestLightRefBaseFlattenable> {
+public:
+ TestLightRefBaseFlattenable() = default;
+ explicit TestLightRefBaseFlattenable(int32_t v) : value(v) {}
+
+ // Flattenable protocol
+ size_t getFlattenedSize() const { return sizeof(value); }
+ size_t getFdCount() const { return 0; }
+ status_t flatten(void*& buffer, size_t& size, int*& /*fds*/, size_t& /*count*/) const {
+ FlattenableUtils::write(buffer, size, value);
+ return NO_ERROR;
+ }
+ status_t unflatten(void const*& buffer, size_t& size, int const*& /*fds*/, size_t& /*count*/) {
+ FlattenableUtils::read(buffer, size, value);
+ return NO_ERROR;
+ }
+
+ int32_t value = 0;
+};
+
+class TestParcelable : public Parcelable {
+public:
+ TestParcelable() = default;
+ explicit TestParcelable(int32_t value) : mValue(value) {}
+ TestParcelable(const TestParcelable& other) : TestParcelable(other.mValue) {}
+ TestParcelable(TestParcelable&& other) : TestParcelable(other.mValue) {}
+
+ // Parcelable interface
+ status_t writeToParcel(Parcel* parcel) const override { return parcel->writeInt32(mValue); }
+ status_t readFromParcel(const Parcel* parcel) override { return parcel->readInt32(&mValue); }
+
+ int32_t getValue() const { return mValue; }
+ void setValue(int32_t value) { mValue = value; }
+
+private:
+ int32_t mValue = 0;
+};
+
class ExitOnDeath : public IBinder::DeathRecipient {
public:
~ExitOnDeath() override = default;
@@ -161,13 +216,19 @@
SetDeathToken = IBinder::FIRST_CALL_TRANSACTION,
ReturnsNoMemory,
LogicalNot,
+ ModifyEnum,
IncrementFlattenable,
IncrementLightFlattenable,
+ IncrementLightRefBaseFlattenable,
+ IncrementNativeHandle,
IncrementNoCopyNoMove,
+ IncrementParcelableVector,
ToUpper,
CallMeBack,
IncrementInt32,
IncrementUint32,
+ IncrementInt64,
+ IncrementUint64,
IncrementTwo,
Last,
};
@@ -181,15 +242,23 @@
// These are ordered according to their corresponding methods in SafeInterface::ParcelHandler
virtual status_t logicalNot(bool a, bool* notA) const = 0;
+ virtual status_t modifyEnum(TestEnum a, TestEnum* b) const = 0;
virtual status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const = 0;
virtual status_t increment(const TestLightFlattenable& a,
TestLightFlattenable* aPlusOne) const = 0;
+ virtual status_t increment(const sp<TestLightRefBaseFlattenable>& a,
+ sp<TestLightRefBaseFlattenable>* aPlusOne) const = 0;
+ virtual status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const = 0;
virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0;
+ virtual status_t increment(const std::vector<TestParcelable>& a,
+ std::vector<TestParcelable>* aPlusOne) const = 0;
virtual status_t toUpper(const String8& str, String8* upperStr) const = 0;
// As mentioned above, sp<IBinder> is already tested by setDeathToken
virtual void callMeBack(const sp<ICallback>& callback, int32_t a) const = 0;
virtual status_t increment(int32_t a, int32_t* aPlusOne) const = 0;
virtual status_t increment(uint32_t a, uint32_t* aPlusOne) const = 0;
+ virtual status_t increment(int64_t a, int64_t* aPlusOne) const = 0;
+ virtual status_t increment(uint64_t a, uint64_t* aPlusOne) const = 0;
// This tests that input/output parameter interleaving works correctly
virtual status_t increment(int32_t a, int32_t* aPlusOne, int32_t b,
@@ -213,6 +282,10 @@
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
return callRemote<decltype(&ISafeInterfaceTest::logicalNot)>(Tag::LogicalNot, a, notA);
}
+ status_t modifyEnum(TestEnum a, TestEnum* b) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<decltype(&ISafeInterfaceTest::modifyEnum)>(Tag::ModifyEnum, a, b);
+ }
status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const override {
using Signature =
status_t (ISafeInterfaceTest::*)(const TestFlattenable&, TestFlattenable*) const;
@@ -226,12 +299,31 @@
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
return callRemote<Signature>(Tag::IncrementLightFlattenable, a, aPlusOne);
}
+ status_t increment(const sp<TestLightRefBaseFlattenable>& a,
+ sp<TestLightRefBaseFlattenable>* aPlusOne) const override {
+ using Signature = status_t (ISafeInterfaceTest::*)(const sp<TestLightRefBaseFlattenable>&,
+ sp<TestLightRefBaseFlattenable>*) const;
+ return callRemote<Signature>(Tag::IncrementLightRefBaseFlattenable, a, aPlusOne);
+ }
+ status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature =
+ status_t (ISafeInterfaceTest::*)(const sp<NativeHandle>&, sp<NativeHandle>*) const;
+ return callRemote<Signature>(Tag::IncrementNativeHandle, a, aPlusOne);
+ }
status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
NoCopyNoMove* aPlusOne) const;
return callRemote<Signature>(Tag::IncrementNoCopyNoMove, a, aPlusOne);
}
+ status_t increment(const std::vector<TestParcelable>& a,
+ std::vector<TestParcelable>* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature = status_t (ISafeInterfaceTest::*)(const std::vector<TestParcelable>&,
+ std::vector<TestParcelable>*);
+ return callRemote<Signature>(Tag::IncrementParcelableVector, a, aPlusOne);
+ }
status_t toUpper(const String8& str, String8* upperStr) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
return callRemote<decltype(&ISafeInterfaceTest::toUpper)>(Tag::ToUpper, str, upperStr);
@@ -251,6 +343,16 @@
using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
return callRemote<Signature>(Tag::IncrementUint32, a, aPlusOne);
}
+ status_t increment(int64_t a, int64_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature = status_t (ISafeInterfaceTest::*)(int64_t, int64_t*) const;
+ return callRemote<Signature>(Tag::IncrementInt64, a, aPlusOne);
+ }
+ status_t increment(uint64_t a, uint64_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
+ return callRemote<Signature>(Tag::IncrementUint64, a, aPlusOne);
+ }
status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
using Signature =
@@ -290,6 +392,11 @@
*notA = !a;
return NO_ERROR;
}
+ status_t modifyEnum(TestEnum a, TestEnum* b) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *b = (a == TestEnum::INITIAL) ? TestEnum::FINAL : TestEnum::INVALID;
+ return NO_ERROR;
+ }
status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
aPlusOne->value = a.value + 1;
@@ -301,11 +408,42 @@
aPlusOne->value = a.value + 1;
return NO_ERROR;
}
+ status_t increment(const sp<TestLightRefBaseFlattenable>& a,
+ sp<TestLightRefBaseFlattenable>* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *aPlusOne = new TestLightRefBaseFlattenable(a->value + 1);
+ return NO_ERROR;
+ }
+ status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ native_handle* rawHandle = native_handle_create(1 /*numFds*/, 1 /*numInts*/);
+ if (rawHandle == nullptr) return NO_MEMORY;
+
+ // Copy the fd over directly
+ rawHandle->data[0] = dup(a->handle()->data[0]);
+
+ // Increment the int
+ rawHandle->data[1] = a->handle()->data[1] + 1;
+
+ // This cannot fail, as it is just the sp<NativeHandle> taking responsibility for closing
+ // the native_handle when it goes out of scope
+ *aPlusOne = NativeHandle::create(rawHandle, true);
+ return NO_ERROR;
+ }
status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
aPlusOne->setValue(a.getValue() + 1);
return NO_ERROR;
}
+ status_t increment(const std::vector<TestParcelable>& a,
+ std::vector<TestParcelable>* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ aPlusOne->resize(a.size());
+ for (size_t i = 0; i < a.size(); ++i) {
+ (*aPlusOne)[i].setValue(a[i].getValue() + 1);
+ }
+ return NO_ERROR;
+ }
status_t toUpper(const String8& str, String8* upperStr) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
*upperStr = str;
@@ -326,6 +464,16 @@
*aPlusOne = a + 1;
return NO_ERROR;
}
+ status_t increment(int64_t a, int64_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *aPlusOne = a + 1;
+ return NO_ERROR;
+ }
+ status_t increment(uint64_t a, uint64_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *aPlusOne = a + 1;
+ return NO_ERROR;
+ }
status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
*aPlusOne = a + 1;
@@ -349,6 +497,9 @@
case ISafeInterfaceTest::Tag::LogicalNot: {
return callLocal(data, reply, &ISafeInterfaceTest::logicalNot);
}
+ case ISafeInterfaceTest::Tag::ModifyEnum: {
+ return callLocal(data, reply, &ISafeInterfaceTest::modifyEnum);
+ }
case ISafeInterfaceTest::Tag::IncrementFlattenable: {
using Signature = status_t (ISafeInterfaceTest::*)(const TestFlattenable& a,
TestFlattenable* aPlusOne) const;
@@ -360,11 +511,28 @@
TestLightFlattenable* aPlusOne) const;
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
}
+ case ISafeInterfaceTest::Tag::IncrementLightRefBaseFlattenable: {
+ using Signature =
+ status_t (ISafeInterfaceTest::*)(const sp<TestLightRefBaseFlattenable>&,
+ sp<TestLightRefBaseFlattenable>*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::IncrementNativeHandle: {
+ using Signature = status_t (ISafeInterfaceTest::*)(const sp<NativeHandle>&,
+ sp<NativeHandle>*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
case ISafeInterfaceTest::Tag::IncrementNoCopyNoMove: {
using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
NoCopyNoMove* aPlusOne) const;
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
}
+ case ISafeInterfaceTest::Tag::IncrementParcelableVector: {
+ using Signature =
+ status_t (ISafeInterfaceTest::*)(const std::vector<TestParcelable>&,
+ std::vector<TestParcelable>*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
case ISafeInterfaceTest::Tag::ToUpper: {
return callLocal(data, reply, &ISafeInterfaceTest::toUpper);
}
@@ -379,6 +547,14 @@
using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
}
+ case ISafeInterfaceTest::Tag::IncrementInt64: {
+ using Signature = status_t (ISafeInterfaceTest::*)(int64_t, int64_t*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::IncrementUint64: {
+ using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
case ISafeInterfaceTest::Tag::IncrementTwo: {
using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t,
int32_t*) const;
@@ -465,6 +641,14 @@
ASSERT_EQ(!b, notB);
}
+TEST_F(SafeInterfaceTest, TestModifyEnum) {
+ const TestEnum a = TestEnum::INITIAL;
+ TestEnum b = TestEnum::INVALID;
+ status_t result = mSafeInterfaceTest->modifyEnum(a, &b);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(TestEnum::FINAL, b);
+}
+
TEST_F(SafeInterfaceTest, TestIncrementFlattenable) {
const TestFlattenable a{1};
TestFlattenable aPlusOne{0};
@@ -481,6 +665,56 @@
ASSERT_EQ(a.value + 1, aPlusOne.value);
}
+TEST_F(SafeInterfaceTest, TestIncrementLightRefBaseFlattenable) {
+ sp<TestLightRefBaseFlattenable> a = new TestLightRefBaseFlattenable{1};
+ sp<TestLightRefBaseFlattenable> aPlusOne;
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_NE(nullptr, aPlusOne.get());
+ ASSERT_EQ(a->value + 1, aPlusOne->value);
+}
+
+namespace { // Anonymous namespace
+
+bool fdsAreEquivalent(int a, int b) {
+ struct stat statA {};
+ struct stat statB {};
+ if (fstat(a, &statA) != 0) return false;
+ if (fstat(b, &statB) != 0) return false;
+ return (statA.st_dev == statB.st_dev) && (statA.st_ino == statB.st_ino);
+}
+
+} // Anonymous namespace
+
+TEST_F(SafeInterfaceTest, TestIncrementNativeHandle) {
+ // Create an fd we can use to send and receive from the remote process
+ base::unique_fd eventFd{eventfd(0 /*initval*/, 0 /*flags*/)};
+ ASSERT_NE(-1, eventFd);
+
+ // Determine the maximum number of fds this process can have open
+ struct rlimit limit {};
+ ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &limit));
+ uint32_t maxFds = static_cast<uint32_t>(limit.rlim_cur);
+
+ // Perform this test enough times to rule out fd leaks
+ for (uint32_t iter = 0; iter < (2 * maxFds); ++iter) {
+ native_handle* handle = native_handle_create(1 /*numFds*/, 1 /*numInts*/);
+ ASSERT_NE(nullptr, handle);
+ handle->data[0] = dup(eventFd.get());
+ handle->data[1] = 1;
+
+ // This cannot fail, as it is just the sp<NativeHandle> taking responsibility for closing
+ // the native_handle when it goes out of scope
+ sp<NativeHandle> a = NativeHandle::create(handle, true);
+
+ sp<NativeHandle> aPlusOne;
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_TRUE(fdsAreEquivalent(a->handle()->data[0], aPlusOne->handle()->data[0]));
+ ASSERT_EQ(a->handle()->data[1] + 1, aPlusOne->handle()->data[1]);
+ }
+}
+
TEST_F(SafeInterfaceTest, TestIncrementNoCopyNoMove) {
const NoCopyNoMove a{1};
NoCopyNoMove aPlusOne{0};
@@ -489,6 +723,16 @@
ASSERT_EQ(a.getValue() + 1, aPlusOne.getValue());
}
+TEST_F(SafeInterfaceTest, TestIncremementParcelableVector) {
+ const std::vector<TestParcelable> a{TestParcelable{1}, TestParcelable{2}};
+ std::vector<TestParcelable> aPlusOne;
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(a.size(), aPlusOne.size());
+ for (size_t i = 0; i < a.size(); ++i) {
+ ASSERT_EQ(a[i].getValue() + 1, aPlusOne[i].getValue());
+ }
+}
+
TEST_F(SafeInterfaceTest, TestToUpper) {
const String8 str{"Hello, world!"};
String8 upperStr;
@@ -544,6 +788,22 @@
ASSERT_EQ(a + 1, aPlusOne);
}
+TEST_F(SafeInterfaceTest, TestIncrementInt64) {
+ const int64_t a = 1;
+ int64_t aPlusOne = 0;
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementUint64) {
+ const uint64_t a = 1;
+ uint64_t aPlusOne = 0;
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a + 1, aPlusOne);
+}
+
TEST_F(SafeInterfaceTest, TestIncrementTwo) {
const int32_t a = 1;
int32_t aPlusOne = 0;
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
index fe9e05a..13f03b1 100644
--- a/libs/binder/tests/schd-dbg.cpp
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -40,7 +40,7 @@
// GOOD_SYNC_MIN is considered as good
#define GOOD_SYNC_MIN (0.6)
-#define DUMP_PRICISION 3
+#define DUMP_PRESICION 2
string trace_path = "/sys/kernel/debug/tracing";
@@ -246,10 +246,11 @@
double worst = (double)m_worst / 1.0E6;
double average = (double)m_total_time / m_transactions / 1.0E6;
// FIXME: libjson?
- cout << std::setprecision(DUMP_PRICISION) << "{ \"avg\":" << setw(5) << left
- << average << ", \"wst\":" << setw(5) << left << worst
- << ", \"bst\":" << setw(5) << left << best << ", \"miss\":" << setw(5)
- << left << m_miss << ", \"meetR\":" << setw(3) << left
+ int W = DUMP_PRESICION + 2;
+ cout << setprecision(DUMP_PRESICION) << "{ \"avg\":" << setw(W) << left
+ << average << ",\"wst\":" << setw(W) << left << worst
+ << ",\"bst\":" << setw(W) << left << best << ",\"miss\":" << left
+ << m_miss << ",\"meetR\":" << left << setprecision(DUMP_PRESICION + 3)
<< (1.0 - (double)m_miss / m_transactions) << "}";
}
};
@@ -272,8 +273,15 @@
}
}
+typedef struct {
+ void* result;
+ int target;
+} thread_priv_t;
+
static void* thread_start(void* p) {
- Results* results_fifo = (Results*)p;
+ thread_priv_t* priv = (thread_priv_t*)p;
+ int target = priv->target;
+ Results* results_fifo = (Results*)priv->result;
Parcel data, reply;
Tick sta, end;
@@ -281,7 +289,7 @@
thread_dump("fifo-caller");
sta = tickNow();
- status_t ret = workers[0]->transact(BINDER_NOP, data, &reply);
+ status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
end = tickNow();
results_fifo->add_time(tickNano(sta, end));
@@ -291,16 +299,19 @@
}
// create a fifo thread to transact and wait it to finished
-static void thread_transaction(Results* results_fifo) {
+static void thread_transaction(int target, Results* results_fifo) {
+ thread_priv_t thread_priv;
void* dummy;
pthread_t thread;
pthread_attr_t attr;
struct sched_param param;
+ thread_priv.target = target;
+ thread_priv.result = results_fifo;
ASSERT(!pthread_attr_init(&attr));
ASSERT(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO));
param.sched_priority = sched_get_priority_max(SCHED_FIFO);
ASSERT(!pthread_attr_setschedparam(&attr, ¶m));
- ASSERT(!pthread_create(&thread, &attr, &thread_start, results_fifo));
+ ASSERT(!pthread_create(&thread, &attr, &thread_start, &thread_priv));
ASSERT(!pthread_join(thread, &dummy));
}
@@ -316,7 +327,9 @@
sp<IServiceManager> serviceMgr = defaultServiceManager();
sp<BinderWorkerService> service = new BinderWorkerService;
serviceMgr->addService(generateServiceName(num), service);
+ // init done
p.signal();
+ // wait for kick-off
p.wait();
// If client/server pairs, then half the workers are
@@ -338,7 +351,7 @@
int target = num % server_count;
// 1. transaction by fifo thread
- thread_transaction(&results_fifo);
+ thread_transaction(target, &results_fifo);
parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
thread_dump("other-caller");
@@ -356,6 +369,7 @@
p.wait();
p.send(&dummy);
+ // wait for kill
p.wait();
// Client for each pair dump here
if (is_client(num)) {
@@ -367,10 +381,10 @@
<< "\"S\":" << (no_trans - no_sync) << ",\"I\":" << no_trans << ","
<< "\"R\":" << sync_ratio << "," << endl;
- cout << " \"other_ms\":";
+ cout << " \"other_ms\":";
results_other.dump();
cout << "," << endl;
- cout << " \"fifo_ms\": ";
+ cout << " \"fifo_ms\": ";
results_fifo.dump();
cout << endl;
cout << "}," << endl;
@@ -463,12 +477,17 @@
for (int i = 0; i < no_process; i++) {
pipes.push_back(make_process(i, iterations, no_process, payload_size));
}
+ // wait for init done
wait_all(pipes);
+ // kick-off iterations
signal_all(pipes);
+ // wait for completion
wait_all(pipes);
+ // start to send result
signal_all(pipes);
for (int i = 0; i < no_process; i++) {
int status;
+ // kill
pipes[i].signal();
wait(&status);
// the exit status is number of transactions without priority inheritance
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 90ab286..5eafb2c 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -79,11 +79,9 @@
"DisplayEventReceiver.cpp",
"FrameTimestamps.cpp",
"GLConsumer.cpp",
- "GraphicBufferAlloc.cpp",
"GuiConfig.cpp",
"IDisplayEventConnection.cpp",
"IConsumerListener.cpp",
- "IGraphicBufferAlloc.cpp",
"IGraphicBufferConsumer.cpp",
"IGraphicBufferProducer.cpp",
"IProducerListener.cpp",
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 13692eb..4151212 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -79,14 +79,13 @@
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
- const sp<IGraphicBufferAlloc>& allocator,
bool consumerIsSurfaceFlinger) {
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));
+ sp<BufferQueueCore> core(new BufferQueueCore());
LOG_ALWAYS_FATAL_IF(core == NULL,
"BufferQueue: failed to create BufferQueueCore");
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index d66aa1a..cd8e696 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -675,12 +675,13 @@
return NO_ERROR;
}
-void BufferQueueConsumer::setConsumerName(const String8& name) {
+status_t BufferQueueConsumer::setConsumerName(const String8& name) {
ATRACE_CALL();
BQ_LOGV("setConsumerName: '%s'", name.string());
Mutex::Autolock lock(mCore->mMutex);
mCore->mConsumerName = name;
mConsumerName = name;
+ return NO_ERROR;
}
status_t BufferQueueConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
@@ -716,9 +717,10 @@
return NO_ERROR;
}
-sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
+status_t BufferQueueConsumer::getSidebandStream(sp<NativeHandle>* outStream) const {
Mutex::Autolock lock(mCore->mMutex);
- return mCore->mSidebandStream;
+ *outStream = mCore->mSidebandStream;
+ return NO_ERROR;
}
status_t BufferQueueConsumer::getOccupancyHistory(bool forceFlush,
@@ -734,20 +736,22 @@
return NO_ERROR;
}
-void BufferQueueConsumer::dumpState(String8& result, const char* prefix) const {
+status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResult) const {
const IPCThreadState* ipc = IPCThreadState::self();
const pid_t pid = ipc->getCallingPid();
const uid_t uid = ipc->getCallingUid();
if ((uid != AID_SHELL)
&& !PermissionCache::checkPermission(String16(
"android.permission.DUMP"), pid, uid)) {
- result.appendFormat("Permission Denial: can't dump BufferQueueConsumer "
+ outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
"from pid=%d, uid=%d\n", pid, uid);
android_errorWriteWithInfoLog(0x534e4554, "27046057",
static_cast<int32_t>(uid), NULL, 0);
- } else {
- mCore->dumpState(result, prefix);
+ return PERMISSION_DENIED;
}
+
+ mCore->dumpState(prefix, outResult);
+ return NO_ERROR;
}
} // namespace android
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index d653db8..cd94253 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -33,9 +33,7 @@
#include <gui/BufferItem.h>
#include <gui/BufferQueueCore.h>
-#include <gui/GraphicBufferAlloc.h>
#include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferAlloc.h>
#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
#include <private/gui/ComposerService.h>
@@ -54,8 +52,7 @@
return id | counter++;
}
-BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
- mAllocator(allocator),
+BufferQueueCore::BufferQueueCore() :
mMutex(),
mIsAbandoned(false),
mConsumerControlledByApp(false),
@@ -97,30 +94,6 @@
mLastQueuedSlot(INVALID_BUFFER_SLOT),
mUniqueId(getUniqueId())
{
- if (allocator == NULL) {
-
-#ifdef HAVE_NO_SURFACE_FLINGER
- // Without a SurfaceFlinger, allocate in-process. This only makes
- // sense in systems with static SELinux configurations and no
- // applications (since applications need dynamic SELinux policy).
- mAllocator = new GraphicBufferAlloc();
-#else
- // Run time check for headless, where we also allocate in-process.
- char value[PROPERTY_VALUE_MAX];
- property_get("config.headless", value, "0");
- if (atoi(value) == 1) {
- mAllocator = new GraphicBufferAlloc();
- } else {
- sp<ISurfaceComposer> composer(ComposerService::getComposerService());
- mAllocator = composer->createGraphicBufferAlloc();
- }
-#endif // HAVE_NO_SURFACE_FLINGER
-
- if (mAllocator == NULL) {
- BQ_LOGE("createGraphicBufferAlloc failed");
- }
- }
-
int numStartingBuffers = getMaxBufferCountLocked();
for (int s = 0; s < numStartingBuffers; s++) {
mFreeSlots.insert(s);
@@ -133,7 +106,7 @@
BufferQueueCore::~BufferQueueCore() {}
-void BufferQueueCore::dumpState(String8& result, const char* prefix) const {
+void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
Mutex::Autolock lock(mMutex);
String8 fifo;
@@ -148,10 +121,10 @@
++current;
}
- result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
+ outResult->appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
"mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d "
"mAsyncMode=%d, default-size=[%dx%d], default-format=%d, "
- "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix,
+ "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix.string(),
mMaxAcquiredBufferCount, mMaxDequeuedBufferCount,
mDequeueBufferCannotBlock, mAsyncMode, mDefaultWidth,
mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(),
@@ -161,28 +134,28 @@
const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
// A dequeued buffer might be null if it's still being allocated
if (buffer.get()) {
- result.appendFormat("%s%s[%02d:%p] state=%-8s, %p "
- "[%4ux%4u:%4u,%3X]\n", prefix,
+ outResult->appendFormat("%s%s[%02d:%p] state=%-8s, %p "
+ "[%4ux%4u:%4u,%3X]\n", prefix.string(),
(mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
buffer.get(), mSlots[s].mBufferState.string(),
buffer->handle, buffer->width, buffer->height,
buffer->stride, buffer->format);
} else {
- result.appendFormat("%s [%02d:%p] state=%-8s\n", prefix, s,
+ outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s,
buffer.get(), mSlots[s].mBufferState.string());
}
}
for (int s : mFreeBuffers) {
const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
- result.appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n",
- prefix, s, buffer.get(), mSlots[s].mBufferState.string(),
+ outResult->appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n",
+ prefix.string(), s, buffer.get(), mSlots[s].mBufferState.string(),
buffer->handle, buffer->width, buffer->height, buffer->stride,
buffer->format);
}
for (int s : mFreeSlots) {
const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
- result.appendFormat("%s [%02d:%p] state=%-8s\n", prefix, s,
+ outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s,
buffer.get(), mSlots[s].mBufferState.string());
}
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index aef231a..a540ab9 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -34,7 +34,6 @@
#include <gui/BufferQueueProducer.h>
#include <gui/GLConsumer.h>
#include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferAlloc.h>
#include <gui/IProducerListener.h>
#include <utils/Log.h>
@@ -454,8 +453,7 @@
mSlots[found].mBufferState.dequeue();
if ((buffer == NULL) ||
- buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT,
- usage))
+ buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
{
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = NULL;
@@ -503,11 +501,13 @@
} // Autolock scope
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
- status_t error;
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
- sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
- width, height, format, BQ_LAYER_COUNT, usage,
- {mConsumerName.string(), mConsumerName.size()}, &error));
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+ width, height, format, BQ_LAYER_COUNT, usage, usage,
+ {mConsumerName.string(), mConsumerName.size()});
+
+ status_t error = graphicBuffer->initCheck();
+
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
@@ -1337,11 +1337,12 @@
Vector<sp<GraphicBuffer>> buffers;
for (size_t i = 0; i < newBufferCount; ++i) {
- status_t result = NO_ERROR;
- sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
- allocUsage, {mConsumerName.string(), mConsumerName.size()},
- &result));
+ allocUsage, allocUsage, {mConsumerName.string(), mConsumerName.size()});
+
+ status_t result = graphicBuffer->initCheck();
+
if (result != NO_ERROR) {
BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
" %u, usage %u)", width, height, format, usage);
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index d4e4dc3..5c6158c 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -30,7 +30,6 @@
#include <cutils/atomic.h>
#include <gui/BufferItem.h>
-#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/ConsumerBase.h>
@@ -270,7 +269,9 @@
result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned));
if (!mAbandoned) {
- mConsumer->dumpState(result, prefix);
+ String8 consumerState;
+ mConsumer->dumpState(String8(prefix), &consumerState);
+ result.append(consumerState);
}
}
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 55e0d26..c654f08 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -31,7 +31,6 @@
#include <gui/BufferItem.h>
#include <gui/GLConsumer.h>
-#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
deleted file mode 100644
index cc7d403..0000000
--- a/libs/gui/GraphicBufferAlloc.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- **
- ** Copyright 2012 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/GraphicBufferAlloc.h>
-
-#include <log/log.h>
-
-
-namespace android {
-
-GraphicBufferAlloc::GraphicBufferAlloc() = default;
-GraphicBufferAlloc::~GraphicBufferAlloc() = default;
-
-sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
- uint32_t height, PixelFormat format, uint32_t layerCount,
- uint64_t producerUsage, uint64_t consumerUsage,
- std::string requestorName, status_t* error) {
- sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(
- width, height, format, layerCount, producerUsage, consumerUsage,
- std::move(requestorName)));
- status_t err = graphicBuffer->initCheck();
- *error = err;
- if (err != 0 || graphicBuffer->handle == 0) {
- if (err == NO_MEMORY) {
- GraphicBuffer::dumpAllocationsToSystemLog();
- }
- ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
- width, height, layerCount, strerror(-err),
- graphicBuffer->handle);
- graphicBuffer.clear();
- }
- return graphicBuffer;
-}
-
-} // namespace android
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
deleted file mode 100644
index 21a0dd5..0000000
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-// tag as surfaceflinger
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <gui/IGraphicBufferAlloc.h>
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-enum {
- CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
-};
-
-class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
-{
-public:
- explicit BpGraphicBufferAlloc(const sp<IBinder>& impl)
- : BpInterface<IGraphicBufferAlloc>(impl)
- {
- }
-
- virtual ~BpGraphicBufferAlloc();
-
- virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
- uint32_t height, PixelFormat format, uint32_t layerCount,
- uint64_t producerUsage, uint64_t consumerUsage,
- std::string requestorName, status_t* error) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
- data.writeUint32(width);
- data.writeUint32(height);
- data.writeInt32(static_cast<int32_t>(format));
- data.writeUint32(layerCount);
- data.writeUint64(producerUsage);
- data.writeUint64(consumerUsage);
- if (requestorName.empty()) {
- requestorName += "[PID ";
- requestorName += std::to_string(getpid());
- requestorName += ']';
- }
- data.writeUtf8AsUtf16(requestorName);
- remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply);
- sp<GraphicBuffer> graphicBuffer;
- status_t result = reply.readInt32();
- 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.
- }
- *error = result;
- return graphicBuffer;
- }
-};
-
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpGraphicBufferAlloc::~BpGraphicBufferAlloc() {}
-
-IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc");
-
-// ----------------------------------------------------------------------
-
-status_t BnGraphicBufferAlloc::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- // codes that don't require permission check
-
- // BufferReference just keeps a strong reference to a GraphicBuffer until it
- // is destroyed (that is, until no local or remote process have a reference
- // to it).
- class BufferReference : public BBinder {
- sp<GraphicBuffer> mBuffer;
- public:
- explicit BufferReference(const sp<GraphicBuffer>& buffer) : mBuffer(buffer) {}
- };
-
-
- switch (code) {
- case CREATE_GRAPHIC_BUFFER: {
- CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
- uint32_t width = data.readUint32();
- uint32_t height = data.readUint32();
- PixelFormat format = static_cast<PixelFormat>(data.readInt32());
- uint32_t layerCount = data.readUint32();
- uint64_t producerUsage = data.readUint64();
- uint64_t consumerUsage = data.readUint64();
- status_t error = NO_ERROR;
- std::string requestorName;
- data.readUtf8FromUtf16(&requestorName);
- sp<GraphicBuffer> result = createGraphicBuffer(width, height,
- format, layerCount, producerUsage, consumerUsage,
- requestorName, &error);
- reply->writeInt32(error);
- if (result != 0) {
- reply->write(*result);
- // We add a BufferReference to this parcel to make sure the
- // buffer stays alive until the GraphicBuffer object on
- // the other side has been created.
- // This is needed so that the buffer handle can be
- // registered before the buffer is destroyed on implementations
- // that do not use file-descriptors to track their buffers.
- reply->writeStrongBinder( new BufferReference(result) );
- }
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-}; // namespace android
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index ef770e8..568c318 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -14,28 +14,24 @@
* limitations under the License.
*/
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/NativeHandle.h>
-#include <utils/String8.h>
-
-#include <binder/Parcel.h>
-#include <binder/IInterface.h>
+#include <gui/IGraphicBufferConsumer.h>
#include <gui/BufferItem.h>
#include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferConsumer.h>
-#include <ui/GraphicBuffer.h>
+#include <binder/Parcel.h>
+
#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
-#include <system/window.h>
+#include <utils/NativeHandle.h>
+#include <utils/String8.h>
namespace android {
-enum {
+namespace { // Anonymous namespace
+
+enum class Tag : uint32_t {
ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
DETACH_BUFFER,
ATTACH_BUFFER,
@@ -54,439 +50,173 @@
GET_SIDEBAND_STREAM,
GET_OCCUPANCY_HISTORY,
DISCARD_FREE_BUFFERS,
- DUMP,
+ DUMP_STATE,
+ LAST = DUMP_STATE,
};
+} // Anonymous namespace
-class BpGraphicBufferConsumer : public BpInterface<IGraphicBufferConsumer>
-{
+class BpGraphicBufferConsumer : public SafeBpInterface<IGraphicBufferConsumer> {
public:
explicit BpGraphicBufferConsumer(const sp<IBinder>& impl)
- : BpInterface<IGraphicBufferConsumer>(impl)
- {
+ : SafeBpInterface<IGraphicBufferConsumer>(impl, "BpGraphicBufferConsumer") {}
+
+ ~BpGraphicBufferConsumer() override;
+
+ status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
+ uint64_t maxFrameNumber) override {
+ using Signature = decltype(&IGraphicBufferConsumer::acquireBuffer);
+ return callRemote<Signature>(Tag::ACQUIRE_BUFFER, buffer, presentWhen, maxFrameNumber);
}
- virtual ~BpGraphicBufferConsumer();
-
- 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;
- }
- result = reply.read(*buffer);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t detachBuffer(int slot) override {
+ using Signature = decltype(&IGraphicBufferConsumer::detachBuffer);
+ return callRemote<Signature>(Tag::DETACH_BUFFER, slot);
}
- virtual status_t detachBuffer(int slot) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeInt32(slot);
- status_t result = remote()->transact(DETACH_BUFFER, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- result = reply.readInt32();
- return result;
+ status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) override {
+ using Signature = decltype(&IGraphicBufferConsumer::attachBuffer);
+ return callRemote<Signature>(Tag::ATTACH_BUFFER, slot, buffer);
}
- virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.write(*buffer.get());
- status_t result = remote()->transact(ATTACH_BUFFER, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- *slot = reply.readInt32();
- result = reply.readInt32();
- return result;
+ status_t releaseBuffer(int buf, uint64_t frameNumber,
+ EGLDisplay display __attribute__((unused)),
+ EGLSyncKHR fence __attribute__((unused)),
+ const sp<Fence>& releaseFence) override {
+ return callRemote<ReleaseBuffer>(Tag::RELEASE_BUFFER, buf, frameNumber, releaseFence);
}
- virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
- EGLDisplay display __attribute__((unused)), EGLSyncKHR fence __attribute__((unused)),
- const sp<Fence>& releaseFence) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeInt32(buf);
- data.writeInt64(static_cast<int64_t>(frameNumber));
- data.write(*releaseFence);
- status_t result = remote()->transact(RELEASE_BUFFER, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) override {
+ using Signature = decltype(&IGraphicBufferConsumer::consumerConnect);
+ return callRemote<Signature>(Tag::CONSUMER_CONNECT, consumer, controlledByApp);
}
- virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(consumer));
- data.writeInt32(controlledByApp);
- status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t consumerDisconnect() override {
+ return callRemote<decltype(&IGraphicBufferConsumer::consumerDisconnect)>(
+ Tag::CONSUMER_DISCONNECT);
}
- virtual status_t consumerDisconnect() {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t getReleasedBuffers(uint64_t* slotMask) override {
+ using Signature = decltype(&IGraphicBufferConsumer::getReleasedBuffers);
+ return callRemote<Signature>(Tag::GET_RELEASED_BUFFERS, slotMask);
}
- virtual status_t getReleasedBuffers(uint64_t* slotMask) {
- Parcel data, reply;
- if (slotMask == NULL) {
- ALOGE("getReleasedBuffers: slotMask must not be NULL");
- return BAD_VALUE;
- }
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- *slotMask = static_cast<uint64_t>(reply.readInt64());
- return reply.readInt32();
+ status_t setDefaultBufferSize(uint32_t width, uint32_t height) override {
+ using Signature = decltype(&IGraphicBufferConsumer::setDefaultBufferSize);
+ return callRemote<Signature>(Tag::SET_DEFAULT_BUFFER_SIZE, width, height);
}
- virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeUint32(width);
- data.writeUint32(height);
- status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t setMaxBufferCount(int bufferCount) override {
+ using Signature = decltype(&IGraphicBufferConsumer::setMaxBufferCount);
+ return callRemote<Signature>(Tag::SET_MAX_BUFFER_COUNT, bufferCount);
}
- virtual status_t setMaxBufferCount(int bufferCount) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeInt32(bufferCount);
- status_t result = remote()->transact(SET_MAX_BUFFER_COUNT, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override {
+ using Signature = decltype(&IGraphicBufferConsumer::setMaxAcquiredBufferCount);
+ return callRemote<Signature>(Tag::SET_MAX_ACQUIRED_BUFFER_COUNT, maxAcquiredBuffers);
}
- virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeInt32(maxAcquiredBuffers);
- status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t setConsumerName(const String8& name) override {
+ using Signature = decltype(&IGraphicBufferConsumer::setConsumerName);
+ return callRemote<Signature>(Tag::SET_CONSUMER_NAME, name);
}
- virtual void setConsumerName(const String8& name) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeString8(name);
- remote()->transact(SET_CONSUMER_NAME, data, &reply);
+ status_t setDefaultBufferFormat(PixelFormat defaultFormat) override {
+ using Signature = decltype(&IGraphicBufferConsumer::setDefaultBufferFormat);
+ return callRemote<Signature>(Tag::SET_DEFAULT_BUFFER_FORMAT, defaultFormat);
}
- virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeInt32(static_cast<int32_t>(defaultFormat));
- status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) override {
+ using Signature = decltype(&IGraphicBufferConsumer::setDefaultBufferDataSpace);
+ return callRemote<Signature>(Tag::SET_DEFAULT_BUFFER_DATA_SPACE, defaultDataSpace);
}
- virtual status_t setDefaultBufferDataSpace(
- android_dataspace defaultDataSpace) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeInt32(static_cast<int32_t>(defaultDataSpace));
- status_t result = remote()->transact(SET_DEFAULT_BUFFER_DATA_SPACE,
- data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t setConsumerUsageBits(uint32_t usage) override {
+ using Signature = decltype(&IGraphicBufferConsumer::setConsumerUsageBits);
+ return callRemote<Signature>(Tag::SET_CONSUMER_USAGE_BITS, usage);
}
- virtual status_t setConsumerUsageBits(uint32_t usage) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeUint32(usage);
- status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t setTransformHint(uint32_t hint) override {
+ using Signature = decltype(&IGraphicBufferConsumer::setTransformHint);
+ return callRemote<Signature>(Tag::SET_TRANSFORM_HINT, hint);
}
- virtual status_t setTransformHint(uint32_t hint) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeUint32(hint);
- status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- return reply.readInt32();
+ status_t getSidebandStream(sp<NativeHandle>* outStream) const override {
+ using Signature = decltype(&IGraphicBufferConsumer::getSidebandStream);
+ return callRemote<Signature>(Tag::GET_SIDEBAND_STREAM, outStream);
}
- virtual sp<NativeHandle> getSidebandStream() const {
- Parcel data, reply;
- status_t err;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) {
- return NULL;
- }
- sp<NativeHandle> stream;
- if (reply.readInt32()) {
- stream = NativeHandle::create(reply.readNativeHandle(), true);
- }
- return stream;
+ status_t getOccupancyHistory(bool forceFlush,
+ std::vector<OccupancyTracker::Segment>* outHistory) override {
+ using Signature = decltype(&IGraphicBufferConsumer::getOccupancyHistory);
+ return callRemote<Signature>(Tag::GET_OCCUPANCY_HISTORY, forceFlush, outHistory);
}
- virtual status_t getOccupancyHistory(bool forceFlush,
- std::vector<OccupancyTracker::Segment>* outHistory) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- status_t error = data.writeBool(forceFlush);
- if (error != NO_ERROR) {
- return error;
- }
- error = remote()->transact(GET_OCCUPANCY_HISTORY, data,
- &reply);
- if (error != NO_ERROR) {
- return error;
- }
- error = reply.readParcelableVector(outHistory);
- if (error != NO_ERROR) {
- return error;
- }
- status_t result = NO_ERROR;
- error = reply.readInt32(&result);
- if (error != NO_ERROR) {
- return error;
- }
- return result;
+ status_t discardFreeBuffers() override {
+ return callRemote<decltype(&IGraphicBufferConsumer::discardFreeBuffers)>(
+ Tag::DISCARD_FREE_BUFFERS);
}
- virtual status_t discardFreeBuffers() {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- status_t error = remote()->transact(DISCARD_FREE_BUFFERS, data, &reply);
- if (error != NO_ERROR) {
- return error;
- }
- int32_t result = NO_ERROR;
- error = reply.readInt32(&result);
- if (error != NO_ERROR) {
- return error;
- }
- return result;
- }
-
- virtual void dumpState(String8& result, const char* prefix) const {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeString8(result);
- data.writeString8(String8(prefix ? prefix : ""));
- remote()->transact(DUMP, data, &reply);
- reply.readString8();
+ status_t dumpState(const String8& prefix, String8* outResult) const override {
+ using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
+ return callRemote<Signature>(Tag::DUMP_STATE, prefix, outResult);
}
};
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpGraphicBufferConsumer::~BpGraphicBufferConsumer() {}
+// Out-of-line virtual method definition to trigger vtable emission in this translation unit
+// (see clang warning -Wweak-vtables)
+BpGraphicBufferConsumer::~BpGraphicBufferConsumer() = default;
IMPLEMENT_META_INTERFACE(GraphicBufferConsumer, "android.gui.IGraphicBufferConsumer");
-// ----------------------------------------------------------------------
-
-status_t BnGraphicBufferConsumer::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case ACQUIRE_BUFFER: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- BufferItem item;
- int64_t presentWhen = data.readInt64();
- 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);
- return NO_ERROR;
- }
- case DETACH_BUFFER: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- int slot = data.readInt32();
- int result = detachBuffer(slot);
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case ATTACH_BUFFER: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- sp<GraphicBuffer> buffer = new GraphicBuffer();
- data.read(*buffer.get());
- int slot = -1;
- int result = attachBuffer(&slot, buffer);
- reply->writeInt32(slot);
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case RELEASE_BUFFER: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- int buf = data.readInt32();
- uint64_t frameNumber = static_cast<uint64_t>(data.readInt64());
- sp<Fence> releaseFence = new Fence();
- status_t err = data.read(*releaseFence);
- if (err) return err;
- status_t result = releaseBuffer(buf, frameNumber,
- EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case CONSUMER_CONNECT: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- sp<IConsumerListener> consumer = IConsumerListener::asInterface( data.readStrongBinder() );
- bool controlledByApp = data.readInt32();
- status_t result = consumerConnect(consumer, controlledByApp);
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case CONSUMER_DISCONNECT: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- status_t result = consumerDisconnect();
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case GET_RELEASED_BUFFERS: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- uint64_t slotMask = 0;
- status_t result = getReleasedBuffers(&slotMask);
- reply->writeInt64(static_cast<int64_t>(slotMask));
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case SET_DEFAULT_BUFFER_SIZE: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- uint32_t width = data.readUint32();
- uint32_t height = data.readUint32();
- status_t result = setDefaultBufferSize(width, height);
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case SET_MAX_BUFFER_COUNT: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- int bufferCount = data.readInt32();
- status_t result = setMaxBufferCount(bufferCount);
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case SET_MAX_ACQUIRED_BUFFER_COUNT: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- int maxAcquiredBuffers = data.readInt32();
- status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers);
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case SET_CONSUMER_NAME: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- setConsumerName( data.readString8() );
- return NO_ERROR;
- }
- case SET_DEFAULT_BUFFER_FORMAT: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- PixelFormat defaultFormat = static_cast<PixelFormat>(data.readInt32());
- status_t result = setDefaultBufferFormat(defaultFormat);
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case SET_DEFAULT_BUFFER_DATA_SPACE: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- android_dataspace defaultDataSpace =
- static_cast<android_dataspace>(data.readInt32());
- status_t result = setDefaultBufferDataSpace(defaultDataSpace);
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case SET_CONSUMER_USAGE_BITS: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- uint32_t usage = data.readUint32();
- status_t result = setConsumerUsageBits(usage);
- reply->writeInt32(result);
- return NO_ERROR;
- }
- case SET_TRANSFORM_HINT: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- uint32_t hint = data.readUint32();
- status_t result = setTransformHint(hint);
- 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 GET_OCCUPANCY_HISTORY: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- bool forceFlush = false;
- status_t error = data.readBool(&forceFlush);
- if (error != NO_ERROR) {
- return error;
- }
- std::vector<OccupancyTracker::Segment> history;
- status_t result = getOccupancyHistory(forceFlush, &history);
- error = reply->writeParcelableVector(history);
- if (error != NO_ERROR) {
- return error;
- }
- error = reply->writeInt32(result);
- if (error != NO_ERROR) {
- return error;
- }
- return NO_ERROR;
- }
- case DISCARD_FREE_BUFFERS: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- status_t result = discardFreeBuffers();
- status_t error = reply->writeInt32(result);
- return error;
- }
- case DUMP: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- String8 result = data.readString8();
- String8 prefix = data.readString8();
- static_cast<IGraphicBufferConsumer*>(this)->dumpState(result, prefix);
- reply->writeString8(result);
- return NO_ERROR;
+status_t BnGraphicBufferConsumer::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ auto tag = static_cast<Tag>(code);
+ switch (tag) {
+ case Tag::ACQUIRE_BUFFER:
+ return callLocal(data, reply, &IGraphicBufferConsumer::acquireBuffer);
+ case Tag::DETACH_BUFFER:
+ return callLocal(data, reply, &IGraphicBufferConsumer::detachBuffer);
+ case Tag::ATTACH_BUFFER:
+ return callLocal(data, reply, &IGraphicBufferConsumer::attachBuffer);
+ case Tag::RELEASE_BUFFER:
+ return callLocal(data, reply, &IGraphicBufferConsumer::releaseHelper);
+ case Tag::CONSUMER_CONNECT:
+ return callLocal(data, reply, &IGraphicBufferConsumer::consumerConnect);
+ case Tag::CONSUMER_DISCONNECT:
+ return callLocal(data, reply, &IGraphicBufferConsumer::consumerDisconnect);
+ case Tag::GET_RELEASED_BUFFERS:
+ return callLocal(data, reply, &IGraphicBufferConsumer::getReleasedBuffers);
+ case Tag::SET_DEFAULT_BUFFER_SIZE:
+ return callLocal(data, reply, &IGraphicBufferConsumer::setDefaultBufferSize);
+ case Tag::SET_MAX_BUFFER_COUNT:
+ return callLocal(data, reply, &IGraphicBufferConsumer::setMaxBufferCount);
+ case Tag::SET_MAX_ACQUIRED_BUFFER_COUNT:
+ return callLocal(data, reply, &IGraphicBufferConsumer::setMaxAcquiredBufferCount);
+ case Tag::SET_CONSUMER_NAME:
+ return callLocal(data, reply, &IGraphicBufferConsumer::setConsumerName);
+ case Tag::SET_DEFAULT_BUFFER_FORMAT:
+ return callLocal(data, reply, &IGraphicBufferConsumer::setDefaultBufferFormat);
+ case Tag::SET_DEFAULT_BUFFER_DATA_SPACE:
+ return callLocal(data, reply, &IGraphicBufferConsumer::setDefaultBufferDataSpace);
+ case Tag::SET_CONSUMER_USAGE_BITS:
+ return callLocal(data, reply, &IGraphicBufferConsumer::setConsumerUsageBits);
+ case Tag::SET_TRANSFORM_HINT:
+ return callLocal(data, reply, &IGraphicBufferConsumer::setTransformHint);
+ case Tag::GET_SIDEBAND_STREAM:
+ return callLocal(data, reply, &IGraphicBufferConsumer::getSidebandStream);
+ case Tag::GET_OCCUPANCY_HISTORY:
+ return callLocal(data, reply, &IGraphicBufferConsumer::getOccupancyHistory);
+ case Tag::DISCARD_FREE_BUFFERS:
+ return callLocal(data, reply, &IGraphicBufferConsumer::discardFreeBuffers);
+ case Tag::DUMP_STATE: {
+ using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
+ return callLocal<Signature>(data, reply, &IGraphicBufferConsumer::dumpState);
}
}
- return BBinder::onTransact(code, data, reply, flags);
}
-}; // namespace android
+} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 4d2692f..2516fb8 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -25,7 +25,6 @@
#include <binder/IServiceManager.h>
#include <gui/IDisplayEventConnection.h>
-#include <gui/IGraphicBufferAlloc.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
@@ -72,14 +71,6 @@
return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
}
- virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply);
- return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder());
- }
-
virtual void setTransactionState(
const Vector<ComposerState>& state,
const Vector<DisplayState>& displays,
@@ -505,12 +496,6 @@
reply->writeStrongBinder(b);
return NO_ERROR;
}
- case CREATE_GRAPHIC_BUFFER_ALLOC: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> b = IInterface::asBinder(createGraphicBufferAlloc());
- reply->writeStrongBinder(b);
- return NO_ERROR;
- }
case SET_TRANSACTION_STATE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 55e6fbf..893c0a6 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -1057,7 +1057,7 @@
// Check no free buffers in dump
String8 dumpString;
- mConsumer->dumpState(dumpString, nullptr);
+ mConsumer->dumpState(String8{}, &dumpString);
// Parse the dump to ensure that all buffer slots that are FREE also
// have a null GraphicBuffer
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index cf3d1b2..08d6715 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -377,9 +377,6 @@
const sp<IGraphicBufferProducer>& /* parent */) override {
return nullptr;
}
- sp<IGraphicBufferAlloc> createGraphicBufferAlloc() override {
- return nullptr;
- }
sp<IDisplayEventConnection> createDisplayEventConnection() override {
return nullptr;
}
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index a38b4dc..5812831 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -33,7 +33,7 @@
#include <private/android/AHardwareBufferHelpers.h>
-static constexpr int kDataBufferSize = 64 * sizeof(int); // 64 ints
+static constexpr int kFdBufferSize = 128 * sizeof(int); // 128 ints
using namespace android;
@@ -70,7 +70,7 @@
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog();
}
- ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
+ ALOGE("GraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
desc->width, desc->height, desc->layers, strerror(-err), gbuffer->handle);
return err;
}
@@ -169,7 +169,7 @@
iov[0].iov_base = data.get();
iov[0].iov_len = flattenedSize;
- char buf[CMSG_SPACE(kDataBufferSize)];
+ char buf[CMSG_SPACE(kFdBufferSize)];
struct msghdr msg = {
.msg_control = buf,
.msg_controllen = sizeof(buf),
@@ -197,11 +197,13 @@
int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer) {
if (!outBuffer) return BAD_VALUE;
- char dataBuf[CMSG_SPACE(kDataBufferSize)];
- char fdBuf[CMSG_SPACE(kDataBufferSize)];
+ static constexpr int kMessageBufferSize = 4096 * sizeof(int);
+
+ std::unique_ptr<char[]> dataBuf(new char[kMessageBufferSize]);
+ char fdBuf[CMSG_SPACE(kFdBufferSize)];
struct iovec iov[1];
- iov[0].iov_base = dataBuf;
- iov[0].iov_len = sizeof(dataBuf);
+ iov[0].iov_base = dataBuf.get();
+ iov[0].iov_len = kMessageBufferSize;
struct msghdr msg = {
.msg_control = fdBuf,
diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp
new file mode 100644
index 0000000..13af470
--- /dev/null
+++ b/libs/vr/libbroadcastring/Android.bp
@@ -0,0 +1,35 @@
+cc_library_static {
+ name: "libbroadcastring",
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "libbase",
+ ],
+ export_shared_lib_headers: [
+ "libbase",
+ ],
+}
+
+cc_test {
+ name: "broadcast_ring_tests",
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ srcs: [
+ "broadcast_ring_test.cc",
+ ],
+ static_libs: [
+ "libbroadcastring",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+}
diff --git a/libs/vr/libbroadcastring/broadcast_ring_test.cc b/libs/vr/libbroadcastring/broadcast_ring_test.cc
new file mode 100644
index 0000000..dfdd4ef
--- /dev/null
+++ b/libs/vr/libbroadcastring/broadcast_ring_test.cc
@@ -0,0 +1,866 @@
+#include "libbroadcastring/broadcast_ring.h"
+
+#include <stdlib.h>
+#include <memory>
+#include <thread> // NOLINT
+#include <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace dvr {
+namespace {
+
+template <uint32_t N>
+struct alignas(8) Aligned {
+ char v[N];
+};
+
+template <uint32_t N>
+struct alignas(8) Sized {
+ Sized() { Clear(); }
+ explicit Sized(char c) { Fill(c); }
+ char v[sizeof(Aligned<N>)];
+ void Clear() { memset(v, 0, sizeof(v)); }
+ void Fill(char c) { memset(v, c, sizeof(v)); }
+ static Sized Pattern(uint8_t c) {
+ Sized sized;
+ for (size_t i = 0; i < sizeof(v); ++i) {
+ sized.v[i] = static_cast<char>(c + i);
+ }
+ return sized;
+ }
+ bool operator==(const Sized& right) const {
+ static_assert(sizeof(*this) == sizeof(v), "Size mismatch");
+ return !memcmp(v, right.v, sizeof(v));
+ }
+ template <typename SmallerSized>
+ SmallerSized Truncate() const {
+ SmallerSized val;
+ static_assert(sizeof(val.v) <= sizeof(v), "Cannot truncate to larger size");
+ memcpy(val.v, v, sizeof(val.v));
+ return val;
+ }
+};
+
+char FillChar(int val) { return static_cast<char>(val); }
+
+struct FakeMmap {
+ explicit FakeMmap(size_t size) : size(size), data(new char[size]) {}
+ size_t size;
+ std::unique_ptr<char[]> data;
+ void* mmap() { return static_cast<void*>(data.get()); }
+};
+
+template <typename Ring>
+FakeMmap CreateRing(Ring* ring, uint32_t count) {
+ FakeMmap mmap(Ring::MemorySize(count));
+ *ring = Ring::Create(mmap.mmap(), mmap.size, count);
+ return mmap;
+}
+
+template <typename RecordType, bool StaticSize = false,
+ uint32_t StaticCount = 0, uint32_t MaxReserved = 1,
+ uint32_t MinAvailable = 0>
+struct Traits {
+ using Record = RecordType;
+ static constexpr bool kUseStaticRecordSize = StaticSize;
+ static constexpr uint32_t kStaticRecordCount = StaticCount;
+ static constexpr uint32_t kMaxReservedRecords = MaxReserved;
+ static constexpr uint32_t kMinAvailableRecords = MinAvailable;
+ static constexpr uint32_t kMinRecordCount = MaxReserved + MinAvailable;
+};
+
+template <typename Record, bool StaticSize = false, uint32_t MaxReserved = 1,
+ uint32_t MinAvailable = 7>
+struct TraitsDynamic
+ : public Traits<Record, StaticSize, 0, MaxReserved, MinAvailable> {
+ using Ring = BroadcastRing<Record, TraitsDynamic>;
+ static uint32_t MinCount() { return MaxReserved + MinAvailable; }
+};
+
+template <typename Record, uint32_t StaticCount = 1, bool StaticSize = true,
+ uint32_t MaxReserved = 1, uint32_t MinAvailable = 0>
+struct TraitsStatic
+ : public Traits<Record, true, StaticCount, MaxReserved, MinAvailable> {
+ using Ring = BroadcastRing<Record, TraitsStatic>;
+ static uint32_t MinCount() { return StaticCount; }
+};
+
+using Dynamic_8_NxM = TraitsDynamic<Sized<8>>;
+using Dynamic_16_NxM = TraitsDynamic<Sized<16>>;
+using Dynamic_32_NxM = TraitsDynamic<Sized<32>>;
+using Dynamic_32_32xM = TraitsDynamic<Sized<32>, true>;
+using Dynamic_16_NxM_1plus0 = TraitsDynamic<Sized<16>, false, 1, 0>;
+using Dynamic_16_NxM_1plus1 = TraitsDynamic<Sized<16>, false, 1, 1>;
+using Dynamic_16_NxM_5plus11 = TraitsDynamic<Sized<16>, false, 5, 11>;
+using Dynamic_256_NxM_1plus0 = TraitsDynamic<Sized<256>, false, 1, 0>;
+
+using Static_8_8x1 = TraitsStatic<Sized<8>, 1>;
+using Static_8_8x16 = TraitsStatic<Sized<8>, 16>;
+using Static_16_16x8 = TraitsStatic<Sized<16>, 8>;
+using Static_16_16x16 = TraitsStatic<Sized<16>, 16>;
+using Static_16_16x32 = TraitsStatic<Sized<16>, 32>;
+using Static_32_Nx8 = TraitsStatic<Sized<32>, 8, false>;
+
+using TraitsList = ::testing::Types<Dynamic_8_NxM, //
+ Dynamic_16_NxM, //
+ Dynamic_32_NxM, //
+ Dynamic_32_32xM, //
+ Dynamic_16_NxM_1plus0, //
+ Dynamic_16_NxM_1plus1, //
+ Dynamic_16_NxM_5plus11, //
+ Dynamic_256_NxM_1plus0, //
+ Static_8_8x1, //
+ Static_8_8x16, //
+ Static_16_16x8, //
+ Static_16_16x16, //
+ Static_16_16x32, //
+ Static_32_Nx8>;
+
+} // namespace
+
+template <typename T>
+class BroadcastRingTest : public ::testing::Test {};
+
+TYPED_TEST_CASE(BroadcastRingTest, TraitsList);
+
+TYPED_TEST(BroadcastRingTest, Geometry) {
+ using Record = typename TypeParam::Record;
+ using Ring = typename TypeParam::Ring;
+ Ring ring;
+ auto mmap = CreateRing(&ring, Ring::Traits::MinCount());
+ EXPECT_EQ(Ring::Traits::MinCount(), ring.record_count());
+ EXPECT_EQ(sizeof(Record), ring.record_size());
+}
+
+TYPED_TEST(BroadcastRingTest, PutGet) {
+ using Record = typename TypeParam::Record;
+ using Ring = typename TypeParam::Ring;
+ Ring ring;
+ auto mmap = CreateRing(&ring, Ring::Traits::MinCount());
+ const uint32_t oldest_sequence_at_start = ring.GetOldestSequence();
+ const uint32_t next_sequence_at_start = ring.GetNextSequence();
+ {
+ uint32_t sequence = oldest_sequence_at_start;
+ Record record;
+ EXPECT_FALSE(ring.Get(&sequence, &record));
+ EXPECT_EQ(oldest_sequence_at_start, sequence);
+ EXPECT_EQ(Record(), record);
+ }
+ const Record original_record(0x1a);
+ ring.Put(original_record);
+ {
+ uint32_t sequence = next_sequence_at_start;
+ Record record;
+ EXPECT_TRUE(ring.Get(&sequence, &record));
+ EXPECT_EQ(next_sequence_at_start, sequence);
+ EXPECT_EQ(original_record, record);
+ }
+ {
+ uint32_t sequence = next_sequence_at_start + 1;
+ Record record;
+ EXPECT_FALSE(ring.Get(&sequence, &record));
+ EXPECT_EQ(next_sequence_at_start + 1, sequence);
+ EXPECT_EQ(Record(), record);
+ }
+}
+
+TYPED_TEST(BroadcastRingTest, FillOnce) {
+ using Record = typename TypeParam::Record;
+ using Ring = typename TypeParam::Ring;
+ Ring ring;
+ auto mmap = CreateRing(&ring, Ring::Traits::MinCount());
+ const uint32_t next_sequence_at_start = ring.GetNextSequence();
+ for (uint32_t i = 0; i < ring.record_count(); ++i)
+ ring.Put(Record(FillChar(i)));
+ for (uint32_t i = 0; i < ring.record_count(); ++i) {
+ const uint32_t expected_sequence = next_sequence_at_start + i;
+ const Record expected_record(FillChar(i));
+ {
+ uint32_t sequence = ring.GetOldestSequence() + i;
+ Record record;
+ EXPECT_TRUE(ring.Get(&sequence, &record));
+ EXPECT_EQ(expected_sequence, sequence);
+ EXPECT_EQ(expected_record, record);
+ }
+ }
+ {
+ uint32_t sequence = ring.GetOldestSequence() + ring.record_count();
+ Record record;
+ EXPECT_FALSE(ring.Get(&sequence, &record));
+ }
+}
+
+TYPED_TEST(BroadcastRingTest, FillTwice) {
+ using Record = typename TypeParam::Record;
+ using Ring = typename TypeParam::Ring;
+ Ring ring;
+ auto mmap = CreateRing(&ring, Ring::Traits::MinCount());
+ const uint32_t next_sequence_at_start = ring.GetNextSequence();
+ for (uint32_t i = 0; i < 2 * ring.record_count(); ++i) {
+ const Record newest_record(FillChar(i));
+ ring.Put(newest_record);
+
+ const uint32_t newest_sequence = next_sequence_at_start + i;
+ const uint32_t records_available = std::min(i + 1, ring.record_count());
+ const uint32_t oldest_sequence = newest_sequence - records_available + 1;
+ EXPECT_EQ(newest_sequence, ring.GetNewestSequence());
+ EXPECT_EQ(oldest_sequence, ring.GetOldestSequence());
+ EXPECT_EQ(newest_sequence + 1, ring.GetNextSequence());
+
+ for (uint32_t j = 0; j < records_available; ++j) {
+ const uint32_t sequence_jth_newest = newest_sequence - j;
+ const Record record_jth_newest(FillChar(i - j));
+
+ {
+ uint32_t sequence = sequence_jth_newest;
+ Record record;
+ EXPECT_TRUE(ring.Get(&sequence, &record));
+ EXPECT_EQ(sequence_jth_newest, sequence);
+ EXPECT_EQ(record_jth_newest, record);
+ }
+
+ {
+ uint32_t sequence = sequence_jth_newest;
+ Record record;
+ EXPECT_TRUE(ring.GetNewest(&sequence, &record));
+ EXPECT_EQ(newest_sequence, sequence);
+ EXPECT_EQ(newest_record, record);
+ }
+ }
+
+ const Record oldest_record(
+ FillChar(i + (oldest_sequence - newest_sequence)));
+ const uint32_t sequence_0th_overwritten = oldest_sequence - 1;
+ const uint32_t sequence_0th_future = newest_sequence + 1;
+ const uint32_t sequence_1st_future = newest_sequence + 2;
+
+ {
+ uint32_t sequence = sequence_0th_overwritten;
+ Record record;
+ EXPECT_TRUE(ring.Get(&sequence, &record));
+ EXPECT_EQ(oldest_sequence, sequence);
+ EXPECT_EQ(oldest_record, record);
+ }
+
+ {
+ uint32_t sequence = sequence_0th_overwritten;
+ Record record;
+ EXPECT_TRUE(ring.GetNewest(&sequence, &record));
+ EXPECT_EQ(newest_sequence, sequence);
+ EXPECT_EQ(newest_record, record);
+ }
+
+ {
+ uint32_t sequence = sequence_0th_future;
+ Record record;
+ EXPECT_FALSE(ring.Get(&sequence, &record));
+ EXPECT_EQ(sequence_0th_future, sequence);
+ EXPECT_EQ(Record(), record);
+ }
+
+ {
+ uint32_t sequence = sequence_0th_future;
+ Record record;
+ EXPECT_FALSE(ring.GetNewest(&sequence, &record));
+ EXPECT_EQ(sequence_0th_future, sequence);
+ EXPECT_EQ(Record(), record);
+ }
+
+ {
+ uint32_t sequence = sequence_1st_future;
+ Record record;
+ EXPECT_TRUE(ring.Get(&sequence, &record));
+ EXPECT_EQ(oldest_sequence, sequence);
+ EXPECT_EQ(oldest_record, record);
+ }
+
+ {
+ uint32_t sequence = sequence_1st_future;
+ Record record;
+ EXPECT_TRUE(ring.GetNewest(&sequence, &record));
+ EXPECT_EQ(newest_sequence, sequence);
+ EXPECT_EQ(newest_record, record);
+ }
+ }
+}
+
+TYPED_TEST(BroadcastRingTest, Import) {
+ using Record = typename TypeParam::Record;
+ using Ring = typename TypeParam::Ring;
+ Ring ring;
+ auto mmap = CreateRing(&ring, Ring::Traits::MinCount());
+
+ const uint32_t sequence_0 = ring.GetNextSequence();
+ const uint32_t sequence_1 = ring.GetNextSequence() + 1;
+ const Record record_0 = Record::Pattern(0x00);
+ const Record record_1 = Record::Pattern(0x80);
+ ring.Put(record_0);
+ ring.Put(record_1);
+
+ {
+ Ring imported_ring;
+ bool import_ok;
+ std::tie(imported_ring, import_ok) = Ring::Import(mmap.mmap(), mmap.size);
+ EXPECT_TRUE(import_ok);
+ EXPECT_EQ(ring.record_size(), imported_ring.record_size());
+ EXPECT_EQ(ring.record_count(), imported_ring.record_count());
+
+ if (ring.record_count() != 1) {
+ uint32_t sequence = sequence_0;
+ Record imported_record;
+ EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record));
+ EXPECT_EQ(sequence_0, sequence);
+ EXPECT_EQ(record_0, imported_record);
+ }
+
+ {
+ uint32_t sequence = sequence_1;
+ Record imported_record;
+ EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record));
+ EXPECT_EQ(sequence_1, sequence);
+ EXPECT_EQ(record_1, imported_record);
+ }
+ }
+}
+
+TEST(BroadcastRingTest, ShouldFailImportIfStaticSizeMismatch) {
+ using OriginalRing = typename Static_16_16x16::Ring;
+ using RecordSizeMismatchRing = typename Static_8_8x16::Ring;
+ using RecordCountMismatchRing = typename Static_16_16x8::Ring;
+
+ OriginalRing original_ring;
+ auto mmap = CreateRing(&original_ring, OriginalRing::Traits::MinCount());
+
+ {
+ using ImportedRing = RecordSizeMismatchRing;
+ ImportedRing imported_ring;
+ bool import_ok;
+ std::tie(imported_ring, import_ok) =
+ ImportedRing::Import(mmap.mmap(), mmap.size);
+ EXPECT_FALSE(import_ok);
+ auto mmap_imported =
+ CreateRing(&imported_ring, ImportedRing::Traits::MinCount());
+ EXPECT_NE(original_ring.record_size(), imported_ring.record_size());
+ EXPECT_EQ(original_ring.record_count(), imported_ring.record_count());
+ }
+
+ {
+ using ImportedRing = RecordCountMismatchRing;
+ ImportedRing imported_ring;
+ bool import_ok;
+ std::tie(imported_ring, import_ok) =
+ ImportedRing::Import(mmap.mmap(), mmap.size);
+ EXPECT_FALSE(import_ok);
+ auto mmap_imported =
+ CreateRing(&imported_ring, ImportedRing::Traits::MinCount());
+ EXPECT_EQ(original_ring.record_size(), imported_ring.record_size());
+ EXPECT_NE(original_ring.record_count(), imported_ring.record_count());
+ }
+}
+
+TEST(BroadcastRingTest, ShouldFailImportIfDynamicSizeGrows) {
+ using OriginalRing = typename Dynamic_8_NxM::Ring;
+ using RecordSizeGrowsRing = typename Dynamic_16_NxM::Ring;
+
+ OriginalRing original_ring;
+ auto mmap = CreateRing(&original_ring, OriginalRing::Traits::MinCount());
+
+ {
+ using ImportedRing = RecordSizeGrowsRing;
+ ImportedRing imported_ring;
+ bool import_ok;
+ std::tie(imported_ring, import_ok) =
+ ImportedRing::Import(mmap.mmap(), mmap.size);
+ EXPECT_FALSE(import_ok);
+ auto mmap_imported =
+ CreateRing(&imported_ring, ImportedRing::Traits::MinCount());
+ EXPECT_LT(original_ring.record_size(), imported_ring.record_size());
+ EXPECT_EQ(original_ring.record_count(), imported_ring.record_count());
+ }
+}
+
+TEST(BroadcastRingTest, ShouldFailImportIfCountTooSmall) {
+ using OriginalRing = typename Dynamic_16_NxM_1plus0::Ring;
+ using MinCountRing = typename Dynamic_16_NxM_1plus1::Ring;
+
+ OriginalRing original_ring;
+ auto mmap = CreateRing(&original_ring, OriginalRing::Traits::MinCount());
+
+ {
+ using ImportedRing = MinCountRing;
+ ImportedRing imported_ring;
+ bool import_ok;
+ std::tie(imported_ring, import_ok) =
+ ImportedRing::Import(mmap.mmap(), mmap.size);
+ EXPECT_FALSE(import_ok);
+ auto mmap_imported =
+ CreateRing(&imported_ring, ImportedRing::Traits::MinCount());
+ EXPECT_EQ(original_ring.record_size(), imported_ring.record_size());
+ EXPECT_LT(original_ring.record_count(), imported_ring.record_count());
+ }
+}
+
+TEST(BroadcastRingTest, ShouldFailImportIfMmapTooSmall) {
+ using OriginalRing = typename Dynamic_16_NxM::Ring;
+
+ OriginalRing original_ring;
+ auto mmap = CreateRing(&original_ring, OriginalRing::Traits::MinCount());
+
+ {
+ using ImportedRing = OriginalRing;
+ ImportedRing imported_ring;
+ bool import_ok;
+ const size_t kMinSize =
+ ImportedRing::MemorySize(original_ring.record_count());
+ std::tie(imported_ring, import_ok) = ImportedRing::Import(mmap.mmap(), 0);
+ EXPECT_FALSE(import_ok);
+ std::tie(imported_ring, import_ok) =
+ ImportedRing::Import(mmap.mmap(), kMinSize - 1);
+ EXPECT_FALSE(import_ok);
+ std::tie(imported_ring, import_ok) =
+ ImportedRing::Import(mmap.mmap(), kMinSize);
+ EXPECT_TRUE(import_ok);
+ EXPECT_EQ(original_ring.record_size(), imported_ring.record_size());
+ EXPECT_EQ(original_ring.record_count(), imported_ring.record_count());
+ }
+}
+
+TEST(BroadcastRingTest, ShouldImportIfDynamicSizeShrinks) {
+ using OriginalRing = typename Dynamic_16_NxM::Ring;
+ using RecordSizeShrinksRing = typename Dynamic_8_NxM::Ring;
+
+ OriginalRing original_ring;
+ auto mmap = CreateRing(&original_ring, OriginalRing::Traits::MinCount());
+
+ using OriginalRecord = typename OriginalRing::Record;
+ const uint32_t original_sequence_0 = original_ring.GetNextSequence();
+ const uint32_t original_sequence_1 = original_ring.GetNextSequence() + 1;
+ const OriginalRecord original_record_0 = OriginalRecord::Pattern(0x00);
+ const OriginalRecord original_record_1 = OriginalRecord::Pattern(0x80);
+ original_ring.Put(original_record_0);
+ original_ring.Put(original_record_1);
+
+ {
+ using ImportedRing = RecordSizeShrinksRing;
+ using ImportedRecord = typename ImportedRing::Record;
+ ImportedRing imported_ring;
+ bool import_ok;
+ std::tie(imported_ring, import_ok) =
+ ImportedRing::Import(mmap.mmap(), mmap.size);
+ EXPECT_TRUE(import_ok);
+ EXPECT_EQ(original_ring.record_size(), imported_ring.record_size());
+ EXPECT_EQ(original_ring.record_count(), imported_ring.record_count());
+ EXPECT_GT(sizeof(OriginalRecord), sizeof(ImportedRecord));
+
+ {
+ uint32_t sequence = original_sequence_0;
+ ImportedRecord shrunk_record;
+ EXPECT_TRUE(imported_ring.Get(&sequence, &shrunk_record));
+ EXPECT_EQ(original_sequence_0, sequence);
+ EXPECT_EQ(original_record_0.Truncate<ImportedRecord>(), shrunk_record);
+ }
+
+ {
+ uint32_t sequence = original_sequence_1;
+ ImportedRecord shrunk_record;
+ EXPECT_TRUE(imported_ring.Get(&sequence, &shrunk_record));
+ EXPECT_EQ(original_sequence_1, sequence);
+ EXPECT_EQ(original_record_1.Truncate<ImportedRecord>(), shrunk_record);
+ }
+ }
+}
+
+TEST(BroadcastRingTest, ShouldImportIfCompatibleDynamicToStatic) {
+ using OriginalRing = typename Dynamic_16_NxM::Ring;
+ using ImportedRing = typename Static_16_16x16::Ring;
+ using OriginalRecord = typename OriginalRing::Record;
+ using ImportedRecord = typename ImportedRing::Record;
+ using StaticRing = ImportedRing;
+
+ OriginalRing original_ring;
+ auto mmap = CreateRing(&original_ring, StaticRing::Traits::MinCount());
+
+ const uint32_t original_sequence_0 = original_ring.GetNextSequence();
+ const uint32_t original_sequence_1 = original_ring.GetNextSequence() + 1;
+ const OriginalRecord original_record_0 = OriginalRecord::Pattern(0x00);
+ const OriginalRecord original_record_1 = OriginalRecord::Pattern(0x80);
+ original_ring.Put(original_record_0);
+ original_ring.Put(original_record_1);
+
+ {
+ ImportedRing imported_ring;
+ bool import_ok;
+ std::tie(imported_ring, import_ok) =
+ ImportedRing::Import(mmap.mmap(), mmap.size);
+ EXPECT_TRUE(import_ok);
+ EXPECT_EQ(original_ring.record_size(), imported_ring.record_size());
+ EXPECT_EQ(original_ring.record_count(), imported_ring.record_count());
+
+ {
+ uint32_t sequence = original_sequence_0;
+ ImportedRecord imported_record;
+ EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record));
+ EXPECT_EQ(original_sequence_0, sequence);
+ EXPECT_EQ(original_record_0, imported_record);
+ }
+
+ {
+ uint32_t sequence = original_sequence_1;
+ ImportedRecord imported_record;
+ EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record));
+ EXPECT_EQ(original_sequence_1, sequence);
+ EXPECT_EQ(original_record_1, imported_record);
+ }
+ }
+}
+
+TEST(BroadcastRingTest, ShouldImportIfCompatibleStaticToDynamic) {
+ using OriginalRing = typename Static_16_16x16::Ring;
+ using ImportedRing = typename Dynamic_16_NxM::Ring;
+ using OriginalRecord = typename OriginalRing::Record;
+ using ImportedRecord = typename ImportedRing::Record;
+ using StaticRing = OriginalRing;
+
+ OriginalRing original_ring;
+ auto mmap = CreateRing(&original_ring, StaticRing::Traits::MinCount());
+
+ const uint32_t original_sequence_0 = original_ring.GetNextSequence();
+ const uint32_t original_sequence_1 = original_ring.GetNextSequence() + 1;
+ const OriginalRecord original_record_0 = OriginalRecord::Pattern(0x00);
+ const OriginalRecord original_record_1 = OriginalRecord::Pattern(0x80);
+ original_ring.Put(original_record_0);
+ original_ring.Put(original_record_1);
+
+ {
+ ImportedRing imported_ring;
+ bool import_ok;
+ std::tie(imported_ring, import_ok) =
+ ImportedRing::Import(mmap.mmap(), mmap.size);
+ EXPECT_TRUE(import_ok);
+ EXPECT_EQ(original_ring.record_size(), imported_ring.record_size());
+ EXPECT_EQ(original_ring.record_count(), imported_ring.record_count());
+
+ {
+ uint32_t sequence = original_sequence_0;
+ ImportedRecord imported_record;
+ EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record));
+ EXPECT_EQ(original_sequence_0, sequence);
+ EXPECT_EQ(original_record_0, imported_record);
+ }
+
+ {
+ uint32_t sequence = original_sequence_1;
+ ImportedRecord imported_record;
+ EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record));
+ EXPECT_EQ(original_sequence_1, sequence);
+ EXPECT_EQ(original_record_1, imported_record);
+ }
+ }
+}
+
+TEST(BroadcastRingTest, ShouldImportIfReadonlyMmap) {
+ using Ring = Dynamic_32_NxM::Ring;
+ using Record = Ring::Record;
+
+ uint32_t record_count = Ring::Traits::MinCount();
+ size_t ring_size = Ring::MemorySize(record_count);
+
+ size_t page_size = sysconf(_SC_PAGESIZE);
+ size_t mmap_size = (ring_size + (page_size - 1)) & ~(page_size - 1);
+ ASSERT_GE(mmap_size, ring_size);
+
+ void* mmap_base = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ ASSERT_NE(MAP_FAILED, mmap_base);
+
+ Ring ring = Ring::Create(mmap_base, mmap_size, record_count);
+ for (uint32_t i = 0; i < record_count; ++i) ring.Put(Record(FillChar(i)));
+
+ ASSERT_EQ(0, mprotect(mmap_base, mmap_size, PROT_READ));
+
+ {
+ Ring imported_ring;
+ bool import_ok;
+ std::tie(imported_ring, import_ok) = Ring::Import(mmap_base, mmap_size);
+ EXPECT_TRUE(import_ok);
+ EXPECT_EQ(ring.record_size(), imported_ring.record_size());
+ EXPECT_EQ(ring.record_count(), imported_ring.record_count());
+
+ uint32_t oldest_sequence = imported_ring.GetOldestSequence();
+ for (uint32_t i = 0; i < record_count; ++i) {
+ uint32_t sequence = oldest_sequence + i;
+ Record record;
+ EXPECT_TRUE(imported_ring.Get(&sequence, &record));
+ EXPECT_EQ(Record(FillChar(i)), record);
+ }
+ }
+
+ ASSERT_EQ(0, munmap(mmap_base, mmap_size));
+}
+
+TEST(BroadcastRingTest, ShouldDieIfPutReadonlyMmap) {
+ using Ring = Dynamic_32_NxM::Ring;
+ using Record = Ring::Record;
+
+ uint32_t record_count = Ring::Traits::MinCount();
+ size_t ring_size = Ring::MemorySize(record_count);
+
+ size_t page_size = sysconf(_SC_PAGESIZE);
+ size_t mmap_size = (ring_size + (page_size - 1)) & ~(page_size - 1);
+ ASSERT_GE(mmap_size, ring_size);
+
+ void* mmap_base = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ ASSERT_NE(MAP_FAILED, mmap_base);
+
+ Ring ring = Ring::Create(mmap_base, mmap_size, record_count);
+ for (uint32_t i = 0; i < record_count; ++i) ring.Put(Record(FillChar(i)));
+
+ ASSERT_EQ(0, mprotect(mmap_base, mmap_size, PROT_READ));
+
+ EXPECT_DEATH_IF_SUPPORTED({ ring.Put(Record(7)); }, "");
+
+ ASSERT_EQ(0, munmap(mmap_base, mmap_size));
+}
+
+TEST(BroadcastRingTest, ShouldDieIfCreationMmapTooSmall) {
+ using Ring = Dynamic_32_NxM::Ring;
+ using Record = Ring::Record;
+
+ uint32_t record_count = Ring::Traits::MinCount();
+ size_t ring_size = Ring::MemorySize(record_count);
+ FakeMmap mmap(ring_size);
+
+ EXPECT_DEATH_IF_SUPPORTED({
+ Ring ring = Ring::Create(mmap.mmap(), ring_size - 1, record_count);
+ }, "");
+
+ Ring ring = Ring::Create(mmap.mmap(), ring_size, record_count);
+
+ ring.Put(Record(3));
+
+ {
+ uint32_t sequence = ring.GetNewestSequence();
+ Record record;
+ EXPECT_TRUE(ring.Get(&sequence, &record));
+ EXPECT_EQ(Record(3), record);
+ }
+}
+
+TEST(BroadcastRingTest, ShouldDieIfCreationMmapMisaligned) {
+ using Ring = Static_8_8x1::Ring;
+ using Record = Ring::Record;
+
+ constexpr int kAlign = Ring::mmap_alignment();
+ constexpr int kMisalign = kAlign / 2;
+ size_t ring_size = Ring::MemorySize();
+ std::unique_ptr<char[]> buf(new char[ring_size + kMisalign]);
+
+ EXPECT_DEATH_IF_SUPPORTED(
+ { Ring ring = Ring::Create(buf.get() + kMisalign, ring_size); }, "");
+
+ Ring ring = Ring::Create(buf.get(), ring_size);
+
+ ring.Put(Record(3));
+
+ {
+ uint32_t sequence = ring.GetNewestSequence();
+ Record record;
+ EXPECT_TRUE(ring.Get(&sequence, &record));
+ EXPECT_EQ(Record(3), record);
+ }
+}
+
+template <typename Ring>
+std::unique_ptr<std::thread> CopyTask(std::atomic<bool>* quit, void* in_base,
+ size_t in_size, void* out_base,
+ size_t out_size) {
+ return std::unique_ptr<std::thread>(
+ new std::thread([quit, in_base, in_size, out_base, out_size]() {
+ using Record = typename Ring::Record;
+
+ bool import_ok;
+ Ring in_ring;
+ Ring out_ring;
+ std::tie(in_ring, import_ok) = Ring::Import(in_base, in_size);
+ ASSERT_TRUE(import_ok);
+ std::tie(out_ring, import_ok) = Ring::Import(out_base, out_size);
+ ASSERT_TRUE(import_ok);
+
+ uint32_t sequence = in_ring.GetOldestSequence();
+ while (!std::atomic_load_explicit(quit, std::memory_order_relaxed)) {
+ Record record;
+ if (in_ring.Get(&sequence, &record)) {
+ out_ring.Put(record);
+ sequence++;
+ }
+ }
+ }));
+}
+
+TEST(BroadcastRingTest, ThreadedCopySingle) {
+ using Ring = Dynamic_32_NxM::Ring;
+ using Record = Ring::Record;
+ Ring in_ring;
+ auto in_mmap = CreateRing(&in_ring, Ring::Traits::MinCount());
+
+ Ring out_ring;
+ auto out_mmap = CreateRing(&out_ring, Ring::Traits::MinCount());
+
+ std::atomic<bool> quit(false);
+ std::unique_ptr<std::thread> copy_task = CopyTask<Ring>(
+ &quit, out_mmap.mmap(), out_mmap.size, in_mmap.mmap(), in_mmap.size);
+
+ const Record out_record(0x1c);
+ out_ring.Put(out_record);
+
+ uint32_t in_sequence = in_ring.GetOldestSequence();
+ Record in_record;
+ while (!in_ring.Get(&in_sequence, &in_record)) {
+ // Do nothing.
+ }
+
+ EXPECT_EQ(out_record, in_record);
+ std::atomic_store_explicit(&quit, true, std::memory_order_relaxed);
+ copy_task->join();
+}
+
+TEST(BroadcastRingTest, ThreadedCopyLossless) {
+ using Ring = Dynamic_32_NxM::Ring;
+ using Record = Ring::Record;
+ Ring in_ring;
+ auto in_mmap = CreateRing(&in_ring, Ring::Traits::MinCount());
+
+ Ring out_ring;
+ auto out_mmap = CreateRing(&out_ring, Ring::Traits::MinCount());
+
+ std::atomic<bool> quit(false);
+ std::unique_ptr<std::thread> copy_task = CopyTask<Ring>(
+ &quit, out_mmap.mmap(), out_mmap.size, in_mmap.mmap(), in_mmap.size);
+
+ constexpr uint32_t kRecordsToProcess = 10000;
+ uint32_t out_records = 0;
+ uint32_t in_records = 0;
+ uint32_t in_sequence = in_ring.GetNextSequence();
+ while (out_records < kRecordsToProcess || in_records < kRecordsToProcess) {
+ if (out_records < kRecordsToProcess &&
+ out_records - in_records < out_ring.record_count()) {
+ const Record out_record(FillChar(out_records));
+ out_ring.Put(out_record);
+ out_records++;
+ }
+
+ Record in_record;
+ while (in_ring.Get(&in_sequence, &in_record)) {
+ EXPECT_EQ(Record(FillChar(in_records)), in_record);
+ in_records++;
+ in_sequence++;
+ }
+ }
+
+ EXPECT_EQ(kRecordsToProcess, out_records);
+ EXPECT_EQ(kRecordsToProcess, in_records);
+
+ std::atomic_store_explicit(&quit, true, std::memory_order_relaxed);
+ copy_task->join();
+}
+
+TEST(BroadcastRingTest, ThreadedCopyLossy) {
+ using Ring = Dynamic_32_NxM::Ring;
+ using Record = Ring::Record;
+ Ring in_ring;
+ auto in_mmap = CreateRing(&in_ring, Ring::Traits::MinCount());
+
+ Ring out_ring;
+ auto out_mmap = CreateRing(&out_ring, Ring::Traits::MinCount());
+
+ std::atomic<bool> quit(false);
+ std::unique_ptr<std::thread> copy_task = CopyTask<Ring>(
+ &quit, out_mmap.mmap(), out_mmap.size, in_mmap.mmap(), in_mmap.size);
+
+ constexpr uint32_t kRecordsToProcess = 100000;
+ uint32_t out_records = 0;
+ uint32_t in_records = 0;
+ uint32_t in_sequence = in_ring.GetNextSequence();
+ while (out_records < kRecordsToProcess) {
+ const Record out_record(FillChar(out_records));
+ out_ring.Put(out_record);
+ out_records++;
+
+ Record in_record;
+ if (in_ring.GetNewest(&in_sequence, &in_record)) {
+ EXPECT_EQ(Record(in_record.v[0]), in_record);
+ in_records++;
+ in_sequence++;
+ }
+ }
+
+ EXPECT_EQ(kRecordsToProcess, out_records);
+ EXPECT_GE(kRecordsToProcess, in_records);
+
+ std::atomic_store_explicit(&quit, true, std::memory_order_relaxed);
+ copy_task->join();
+}
+
+template <typename Ring>
+std::unique_ptr<std::thread> CheckFillTask(std::atomic<bool>* quit,
+ void* in_base, size_t in_size) {
+ return std::unique_ptr<std::thread>(
+ new std::thread([quit, in_base, in_size]() {
+ using Record = typename Ring::Record;
+
+ bool import_ok;
+ Ring in_ring;
+ std::tie(in_ring, import_ok) = Ring::Import(in_base, in_size);
+ ASSERT_TRUE(import_ok);
+
+ uint32_t sequence = in_ring.GetOldestSequence();
+ while (!std::atomic_load_explicit(quit, std::memory_order_relaxed)) {
+ Record record;
+ if (in_ring.Get(&sequence, &record)) {
+ ASSERT_EQ(Record(record.v[0]), record);
+ sequence++;
+ }
+ }
+ }));
+}
+
+template <typename Ring>
+void ThreadedOverwriteTorture() {
+ using Record = typename Ring::Record;
+
+ // Maximize overwrites by having few records.
+ const int kMinRecordCount = 1;
+ const int kMaxRecordCount = 4;
+
+ for (int count = kMinRecordCount; count <= kMaxRecordCount; count *= 2) {
+ Ring out_ring;
+ auto out_mmap = CreateRing(&out_ring, count);
+
+ std::atomic<bool> quit(false);
+ std::unique_ptr<std::thread> check_task =
+ CheckFillTask<Ring>(&quit, out_mmap.mmap(), out_mmap.size);
+
+ constexpr int kIterations = 10000;
+ for (int i = 0; i < kIterations; ++i) {
+ const Record record(FillChar(i));
+ out_ring.Put(record);
+ }
+
+ std::atomic_store_explicit(&quit, true, std::memory_order_relaxed);
+ check_task->join();
+ }
+}
+
+TEST(BroadcastRingTest, ThreadedOverwriteTortureSmall) {
+ ThreadedOverwriteTorture<Dynamic_16_NxM_1plus0::Ring>();
+}
+
+TEST(BroadcastRingTest, ThreadedOverwriteTortureLarge) {
+ ThreadedOverwriteTorture<Dynamic_256_NxM_1plus0::Ring>();
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h
new file mode 100644
index 0000000..69cb648
--- /dev/null
+++ b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h
@@ -0,0 +1,668 @@
+#ifndef ANDROID_DVR_BROADCAST_RING_H_
+#define ANDROID_DVR_BROADCAST_RING_H_
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <atomic>
+#include <limits>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "android-base/logging.h"
+
+#if ATOMIC_LONG_LOCK_FREE != 2 || ATOMIC_INT_LOCK_FREE != 2
+#error "This file requires lock free atomic uint32_t and long"
+#endif
+
+namespace android {
+namespace dvr {
+
+struct DefaultRingTraits {
+ // Set this to false to allow compatibly expanding the record size.
+ static constexpr bool kUseStaticRecordSize = false;
+
+ // Set this to a nonzero value to fix the number of records in the ring.
+ static constexpr uint32_t kStaticRecordCount = 0;
+
+ // Set this to the max number of records that can be written simultaneously.
+ static constexpr uint32_t kMaxReservedRecords = 1;
+
+ // Set this to the min number of records that must be readable.
+ static constexpr uint32_t kMinAvailableRecords = 1;
+};
+
+// Nonblocking ring suitable for concurrent single-writer, multi-reader access.
+//
+// Readers never block the writer and thus this is a nondeterministically lossy
+// transport in the absence of external synchronization. Don't use this as a
+// transport when deterministic behavior is required.
+//
+// Readers may have a read-only mapping; each reader's state is a single local
+// sequence number.
+//
+// The implementation takes care to avoid data races on record access.
+// Inconsistent data can only be returned if at least 2^32 records are written
+// during the read-side critical section.
+//
+// In addition, both readers and the writer are careful to avoid accesses
+// outside the bounds of the mmap area passed in during initialization even if
+// there is a misbehaving or malicious task with write access to the mmap area.
+//
+// When dynamic record size is enabled, readers use the record size in the ring
+// header when indexing the ring, so that it is possible to extend the record
+// type without breaking the read-side ABI.
+//
+// Avoid calling Put() in a tight loop; there should be significantly more time
+// between successive puts than it takes to read one record from memory to
+// ensure Get() completes quickly. This requirement should not be difficult to
+// achieve for most practical uses; 4kB puts at 10,000Hz is well below the
+// scaling limit on current mobile chips.
+//
+// Example Writer Usage:
+//
+// using Record = MyRecordType;
+// using Ring = BroadcastRing<Record>;
+//
+// uint32_t record_count = kMyDesiredCount;
+// uint32_t ring_size = Ring::MemorySize(record_count);
+//
+// size_t page_size = sysconf(_SC_PAGESIZE);
+// uint32_t mmap_size = (ring_size + (page_size - 1)) & ~(page_size - 1);
+//
+// // Allocate & map via your preferred mechanism, e.g.
+// int fd = open("/dev/shm/ring_test", O_CREAT|O_RDWR|O_CLOEXEC, 0600);
+// CHECK(fd >= 0);
+// CHECK(!ftruncate(fd, ring_size));
+// void *mmap_base = mmap(nullptr, mmap_size, PROT_READ|PROT_WRITE,
+// MAP_SHARED, fd, 0);
+// CHECK(mmap_base != MAP_FAILED);
+// close(fd);
+//
+// Ring ring = Ring::Create(mmap_base, mmap_size, record_count);
+//
+// while (!done)
+// ring.Put(BuildNextRecordBlocking());
+//
+// CHECK(!munmap(mmap_base, mmap_size));
+//
+// Example Reader Usage:
+//
+// using Record = MyRecordType;
+// using Ring = BroadcastRing<Record>;
+//
+// // Map via your preferred mechanism, e.g.
+// int fd = open("/dev/shm/ring_test", O_RDONLY|O_CLOEXEC);
+// CHECK(fd >= 0);
+// struct stat st;
+// CHECK(!fstat(fd, &st));
+// size_t mmap_size = st.st_size;
+// void *mmap_base = mmap(nullptr, mmap_size, PROT_READ,
+// MAP_SHARED, fd, 0);
+// CHECK(mmap_base != MAP_FAILED);
+// close(fd);
+//
+// Ring ring;
+// bool import_ok;
+// std::tie(ring, import_ok) = Ring::Import(mmap_base, mmap_size);
+// CHECK(import_ok);
+//
+// uint32_t sequence;
+//
+// // Choose starting point (using "0" is unpredictable but not dangerous)
+// sequence = ring.GetOldestSequence(); // The oldest available
+// sequence = ring.GetNewestSequence(); // The newest available
+// sequence = ring.GetNextSequence(); // The next one produced
+//
+// while (!done) {
+// Record record;
+//
+// if (you_want_to_process_all_available_records) {
+// while (ring.Get(&sequence, &record)) {
+// ProcessRecord(sequence, record);
+// sequence++;
+// }
+// } else if (you_want_to_skip_to_the_newest_record) {
+// if (ring.GetNewest(&sequence, &record)) {
+// ProcessRecord(sequence, record);
+// sequence++;
+// }
+// }
+//
+// DoSomethingExpensiveOrBlocking();
+// }
+//
+// CHECK(!munmap(mmap_base, mmap_size));
+//
+template <typename RecordType, typename BaseTraits = DefaultRingTraits>
+class BroadcastRing {
+ public:
+ using Record = RecordType;
+ struct Traits : public BaseTraits {
+ // Must have enough space for writers, plus enough space for readers.
+ static constexpr int kMinRecordCount =
+ BaseTraits::kMaxReservedRecords + BaseTraits::kMinAvailableRecords;
+
+ // Count of zero means dynamic, non-zero means static.
+ static constexpr bool kUseStaticRecordCount =
+ (BaseTraits::kStaticRecordCount != 0);
+
+ // If both record size and count are static then the overall size is too.
+ static constexpr bool kIsStaticSize =
+ BaseTraits::kUseStaticRecordSize && kUseStaticRecordCount;
+ };
+
+ static constexpr bool IsPowerOfTwo(uint32_t size) {
+ return (size & (size - 1)) == 0;
+ }
+
+ // Sanity check the options provided in Traits.
+ static_assert(Traits::kMinRecordCount >= 1, "Min record count too small");
+ static_assert(!Traits::kUseStaticRecordCount ||
+ Traits::kStaticRecordCount >= Traits::kMinRecordCount,
+ "Static record count is too small");
+ static_assert(!Traits::kStaticRecordCount ||
+ IsPowerOfTwo(Traits::kStaticRecordCount),
+ "Static record count is not a power of two");
+ static_assert(std::is_standard_layout<Record>::value,
+ "Record type must be standard layout");
+
+ BroadcastRing() {}
+
+ // Creates a new ring at |mmap| with |record_count| records.
+ //
+ // There must be at least |MemorySize(record_count)| bytes of space already
+ // allocated at |mmap|. The ring does not take ownership.
+ //
+ // Use this function for dynamically sized rings.
+ static BroadcastRing Create(void* mmap, size_t mmap_size,
+ uint32_t record_count) {
+ BroadcastRing ring(mmap);
+ CHECK(ring.ValidateGeometry(mmap_size, sizeof(Record), record_count));
+ ring.InitializeHeader(sizeof(Record), record_count);
+ return ring;
+ }
+
+ // Creates a new ring at |mmap|.
+ //
+ // There must be at least |MemorySize()| bytes of space already allocated at
+ // |mmap|. The ring does not take ownership.
+ //
+ // Use this function for statically sized rings.
+ static BroadcastRing Create(void* mmap, size_t mmap_size) {
+ static_assert(Traits::kUseStaticRecordCount,
+ "Wrong Create() function called for dynamic record count");
+ return Create(mmap, mmap_size, Traits::kStaticRecordCount);
+ }
+
+ // Imports an existing ring at |mmap|.
+ //
+ // Import may fail if the ring parameters in the mmap header are not sensible.
+ // In this case the returned boolean is false; make sure to check this value.
+ static std::tuple<BroadcastRing, bool> Import(void* mmap, size_t mmap_size) {
+ BroadcastRing ring(mmap);
+ uint32_t record_size = 0;
+ uint32_t record_count = 0;
+ if (mmap_size >= sizeof(Header)) {
+ record_size = std::atomic_load_explicit(&ring.header_mmap()->record_size,
+ std::memory_order_relaxed);
+ record_count = std::atomic_load_explicit(
+ &ring.header_mmap()->record_count, std::memory_order_relaxed);
+ }
+ bool ok = ring.ValidateGeometry(mmap_size, record_size, record_count);
+ return std::make_tuple(ring, ok);
+ }
+
+ ~BroadcastRing() {}
+
+ // Calculates the space necessary for a ring of size |record_count|.
+ //
+ // Use this function for dynamically sized rings.
+ static constexpr size_t MemorySize(uint32_t record_count) {
+ return sizeof(Header) + sizeof(Record) * record_count;
+ }
+
+ // Calculates the space necessary for a statically sized ring.
+ //
+ // Use this function for statically sized rings.
+ static constexpr size_t MemorySize() {
+ static_assert(
+ Traits::kUseStaticRecordCount,
+ "Wrong MemorySize() function called for dynamic record count");
+ return MemorySize(Traits::kStaticRecordCount);
+ }
+
+ // Writes a record to the ring.
+ //
+ // The oldest record is overwritten unless the ring is not already full.
+ void Put(const Record& record) {
+ const int kRecordCount = 1;
+ Reserve(kRecordCount);
+ Geometry geometry = GetGeometry();
+ PutRecordInternal(&record, record_mmap_writer(geometry.tail_index));
+ Publish(kRecordCount);
+ }
+
+ // Gets sequence number of the oldest currently available record.
+ uint32_t GetOldestSequence() const {
+ return std::atomic_load_explicit(&header_mmap()->head,
+ std::memory_order_relaxed);
+ }
+
+ // Gets sequence number of the first future record.
+ //
+ // If the returned value is passed to Get() and there is no concurrent Put(),
+ // Get() will return false.
+ uint32_t GetNextSequence() const {
+ return std::atomic_load_explicit(&header_mmap()->tail,
+ std::memory_order_relaxed);
+ }
+
+ // Gets sequence number of the newest currently available record.
+ uint32_t GetNewestSequence() const { return GetNextSequence() - 1; }
+
+ // Copies the oldest available record with sequence at least |*sequence| to
+ // |record|.
+ //
+ // Returns false if there is no recent enough record available.
+ //
+ // Updates |*sequence| with the sequence number of the record returned. To get
+ // the following record, increment this number by one.
+ //
+ // This function synchronizes with two other operations:
+ //
+ // (1) Load-Acquire of |tail|
+ //
+ // Together with the store-release in Publish(), this load-acquire
+ // ensures each store to a record in PutRecordInternal() happens-before
+ // any corresponding load in GetRecordInternal().
+ //
+ // i.e. the stores for the records with sequence numbers < |tail| have
+ // completed from our perspective
+ //
+ // (2) Acquire Fence between record access & final load of |head|
+ //
+ // Together with the release fence in Reserve(), this ensures that if
+ // GetRecordInternal() loads a value stored in some execution of
+ // PutRecordInternal(), then the store of |head| in the Reserve() that
+ // preceeded it happens-before our final load of |head|.
+ //
+ // i.e. if we read a record with sequence number >= |final_head| then
+ // no later store to that record has completed from our perspective
+ bool Get(uint32_t* sequence /*inout*/, Record* record /*out*/) const {
+ for (;;) {
+ uint32_t tail = std::atomic_load_explicit(&header_mmap()->tail,
+ std::memory_order_acquire);
+ uint32_t head = std::atomic_load_explicit(&header_mmap()->head,
+ std::memory_order_relaxed);
+
+ if (tail - head > record_count())
+ continue; // Concurrent modification; re-try.
+
+ if (*sequence - head > tail - head)
+ *sequence = head; // Out of window, skip forward to first available.
+
+ if (*sequence == tail) return false; // No new records available.
+
+ Geometry geometry =
+ CalculateGeometry(record_count(), record_size(), *sequence, tail);
+
+ // Compute address explicitly in case record_size > sizeof(Record).
+ RecordStorage* record_storage = record_mmap_reader(geometry.head_index);
+
+ GetRecordInternal(record_storage, record);
+
+ // NB: It is not sufficient to change this to a load-acquire of |head|.
+ std::atomic_thread_fence(std::memory_order_acquire);
+
+ uint32_t final_head = std::atomic_load_explicit(
+ &header_mmap()->head, std::memory_order_relaxed);
+
+ if (final_head - head > *sequence - head)
+ continue; // Concurrent modification; re-try.
+
+ // Note: Combining the above 4 comparisons gives:
+ // 0 <= final_head - head <= sequence - head < tail - head <= record_count
+ //
+ // We can also write this as:
+ // head <=* final_head <=* sequence <* tail <=* head + record_count
+ //
+ // where <* orders by difference from head: x <* y if x - head < y - head.
+ // This agrees with the order of sequence updates during "put" operations.
+ return true;
+ }
+ }
+
+ // Copies the newest available record with sequence at least |*sequence| to
+ // |record|.
+ //
+ // Returns false if there is no recent enough record available.
+ //
+ // Updates |*sequence| with the sequence number of the record returned. To get
+ // the following record, increment this number by one.
+ bool GetNewest(uint32_t* sequence, Record* record) const {
+ uint32_t newest_sequence = GetNewestSequence();
+ if (*sequence == newest_sequence + 1) return false;
+ *sequence = newest_sequence;
+ return Get(sequence, record);
+ }
+
+ uint32_t record_count() const { return record_count_internal(); }
+ uint32_t record_size() const { return record_size_internal(); }
+ static constexpr uint32_t mmap_alignment() { return alignof(Mmap); }
+
+ private:
+ struct Header {
+ // Record size for reading out of the ring. Writers always write the full
+ // length; readers may need to read a prefix of each record.
+ std::atomic<uint32_t> record_size;
+
+ // Number of records in the ring.
+ std::atomic<uint32_t> record_count;
+
+ // Readable region is [head % record_count, tail % record_count).
+ //
+ // The region in [tail % record_count, head % record_count) was either never
+ // populated or is being updated.
+ //
+ // These are sequences numbers, not indexes - indexes should be computed
+ // with a modulus.
+ //
+ // To ensure consistency:
+ //
+ // (1) Writes advance |head| past any updated records before writing to
+ // them, and advance |tail| after they are written.
+ // (2) Readers check |tail| before reading data and |head| after,
+ // making sure to discard any data that was written to concurrently.
+ std::atomic<uint32_t> head;
+ std::atomic<uint32_t> tail;
+ };
+
+ // Store using the standard word size.
+ using StorageType = long; // NOLINT
+
+ // Always require 8 byte alignment so that the same record sizes are legal on
+ // 32 and 64 bit builds.
+ static constexpr size_t kRecordAlignment = 8;
+ static_assert(kRecordAlignment % sizeof(StorageType) == 0,
+ "Bad record alignment");
+
+ struct RecordStorage {
+ // This is accessed with relaxed atomics to prevent data races on the
+ // contained data, which would be undefined behavior.
+ std::atomic<StorageType> data[sizeof(Record) / sizeof(StorageType)];
+ };
+
+ static_assert(sizeof(StorageType) *
+ std::extent<decltype(RecordStorage::data)>() ==
+ sizeof(Record),
+ "Record length must be a multiple of sizeof(StorageType)");
+
+ struct Geometry {
+ // Static geometry.
+ uint32_t record_count;
+ uint32_t record_size;
+
+ // Copy of atomic sequence counts.
+ uint32_t head;
+ uint32_t tail;
+
+ // First index of readable region.
+ uint32_t head_index;
+
+ // First index of writable region.
+ uint32_t tail_index;
+
+ // Number of records in readable region.
+ uint32_t count;
+
+ // Number of records in writable region.
+ uint32_t space;
+ };
+
+ // Mmap area layout.
+ //
+ // Readers should not index directly into |records| as this is not valid when
+ // dynamic record sizes are used; use record_mmap_reader() instead.
+ struct Mmap {
+ Header header;
+ RecordStorage records[];
+ };
+
+ static_assert(std::is_standard_layout<Mmap>::value,
+ "Mmap must be standard layout");
+ static_assert(sizeof(std::atomic<uint32_t>) == sizeof(uint32_t),
+ "Lockless atomics contain extra state");
+ static_assert(sizeof(std::atomic<StorageType>) == sizeof(StorageType),
+ "Lockless atomics contain extra state");
+
+ explicit BroadcastRing(void* mmap) {
+ CHECK_EQ(0U, reinterpret_cast<uintptr_t>(mmap) % alignof(Mmap));
+ data_.mmap = reinterpret_cast<Mmap*>(mmap);
+ }
+
+ // Initializes the mmap area header for a new ring.
+ void InitializeHeader(uint32_t record_size, uint32_t record_count) {
+ constexpr uint32_t kInitialSequence = -256; // Force an early wrap.
+ std::atomic_store_explicit(&header_mmap()->record_size, record_size,
+ std::memory_order_relaxed);
+ std::atomic_store_explicit(&header_mmap()->record_count, record_count,
+ std::memory_order_relaxed);
+ std::atomic_store_explicit(&header_mmap()->head, kInitialSequence,
+ std::memory_order_relaxed);
+ std::atomic_store_explicit(&header_mmap()->tail, kInitialSequence,
+ std::memory_order_relaxed);
+ }
+
+ // Validates ring geometry.
+ //
+ // Ring geometry is validated carefully on import and then cached. This allows
+ // us to avoid out-of-range accesses even if the parameters in the header are
+ // later changed.
+ bool ValidateGeometry(size_t mmap_size, uint32_t header_record_size,
+ uint32_t header_record_count) {
+ set_record_size(header_record_size);
+ set_record_count(header_record_count);
+
+ if (record_size() != header_record_size) return false;
+ if (record_count() != header_record_count) return false;
+ if (record_count() < Traits::kMinRecordCount) return false;
+ if (record_size() < sizeof(Record)) return false;
+ if (record_size() % kRecordAlignment != 0) return false;
+ if (!IsPowerOfTwo(record_count())) return false;
+
+ size_t memory_size = record_count() * record_size();
+ if (memory_size / record_size() != record_count()) return false;
+ if (memory_size + sizeof(Header) < memory_size) return false;
+ if (memory_size + sizeof(Header) > mmap_size) return false;
+
+ return true;
+ }
+
+ // Copies a record into the ring.
+ //
+ // This is done with relaxed atomics because otherwise it is racy according to
+ // the C++ memory model. This is very low overhead once optimized.
+ static inline void PutRecordInternal(const Record* in, RecordStorage* out) {
+ StorageType data[sizeof(Record) / sizeof(StorageType)];
+ memcpy(data, in, sizeof(*in));
+ for (size_t i = 0; i < std::extent<decltype(data)>(); ++i) {
+ std::atomic_store_explicit(&out->data[i], data[i],
+ std::memory_order_relaxed);
+ }
+ }
+
+ // Copies a record out of the ring.
+ //
+ // This is done with relaxed atomics because otherwise it is racy according to
+ // the C++ memory model. This is very low overhead once optimized.
+ static inline void GetRecordInternal(RecordStorage* in, Record* out) {
+ StorageType data[sizeof(Record) / sizeof(StorageType)];
+ for (size_t i = 0; i < std::extent<decltype(data)>(); ++i) {
+ data[i] =
+ std::atomic_load_explicit(&in->data[i], std::memory_order_relaxed);
+ }
+ memcpy(out, &data, sizeof(*out));
+ }
+
+ // Converts a record's sequence number into a storage index.
+ static uint32_t SequenceToIndex(uint32_t sequence, uint32_t record_count) {
+ return sequence & (record_count - 1);
+ }
+
+ // Computes readable & writable ranges from ring parameters.
+ static Geometry CalculateGeometry(uint32_t record_count, uint32_t record_size,
+ uint32_t head, uint32_t tail) {
+ Geometry geometry;
+ geometry.record_count = record_count;
+ geometry.record_size = record_size;
+ DCHECK_EQ(0U, geometry.record_size % kRecordAlignment);
+ geometry.head = head;
+ geometry.tail = tail;
+ geometry.head_index = SequenceToIndex(head, record_count);
+ geometry.tail_index = SequenceToIndex(tail, record_count);
+ geometry.count = geometry.tail - geometry.head;
+ DCHECK_LE(geometry.count, record_count);
+ geometry.space = geometry.record_count - geometry.count;
+ return geometry;
+ }
+
+ // Gets the current ring readable & writable regions.
+ //
+ // This this is always safe from the writing thread since it is the only
+ // thread allowed to update the header.
+ Geometry GetGeometry() const {
+ return CalculateGeometry(
+ record_count(), record_size(),
+ std::atomic_load_explicit(&header_mmap()->head,
+ std::memory_order_relaxed),
+ std::atomic_load_explicit(&header_mmap()->tail,
+ std::memory_order_relaxed));
+ }
+
+ // Makes space for at least |reserve_count| records.
+ //
+ // There is nothing to prevent overwriting records that have concurrent
+ // readers. We do however ensure that this situation can be detected: the
+ // fence ensures the |head| update will be the first update seen by readers,
+ // and readers check this value after reading and discard data that may have
+ // been concurrently modified.
+ void Reserve(uint32_t reserve_count) {
+ Geometry geometry = GetGeometry();
+ DCHECK_LE(reserve_count, Traits::kMaxReservedRecords);
+ uint32_t needed =
+ (geometry.space >= reserve_count ? 0 : reserve_count - geometry.space);
+
+ std::atomic_store_explicit(&header_mmap()->head, geometry.head + needed,
+ std::memory_order_relaxed);
+
+ // NB: It is not sufficient to change this to a store-release of |head|.
+ std::atomic_thread_fence(std::memory_order_release);
+ }
+
+ // Makes |publish_count| records visible to readers.
+ //
+ // Space must have been reserved by a previous call to Reserve().
+ void Publish(uint32_t publish_count) {
+ Geometry geometry = GetGeometry();
+ DCHECK_LE(publish_count, geometry.space);
+ std::atomic_store_explicit(&header_mmap()->tail,
+ geometry.tail + publish_count,
+ std::memory_order_release);
+ }
+
+ // Helpers to compute addresses in mmap area.
+ Mmap* mmap() const { return data_.mmap; }
+ Header* header_mmap() const { return &data_.mmap->header; }
+ RecordStorage* record_mmap_writer(uint32_t index) const {
+ DCHECK_EQ(sizeof(Record), record_size());
+ return &data_.mmap->records[index];
+ }
+ RecordStorage* record_mmap_reader(uint32_t index) const {
+ if (Traits::kUseStaticRecordSize) {
+ return &data_.mmap->records[index];
+ } else {
+ // Calculate the location of a record in the ring without assuming that
+ // sizeof(Record) == record_size.
+ return reinterpret_cast<RecordStorage*>(
+ reinterpret_cast<char*>(data_.mmap->records) + index * record_size());
+ }
+ }
+
+ // The following horrifying template gunk enables us to store just the mmap
+ // base pointer for compile-time statically sized rings. Dynamically sized
+ // rings also store the validated copy of the record size & count.
+ //
+ // This boils down to: use a compile time constant if available, and otherwise
+ // load the value that was validated on import from a member variable.
+ template <typename T = Traits>
+ typename std::enable_if<T::kUseStaticRecordSize, uint32_t>::type
+ record_size_internal() const {
+ return sizeof(Record);
+ }
+
+ template <typename T = Traits>
+ typename std::enable_if<!T::kUseStaticRecordSize, uint32_t>::type
+ record_size_internal() const {
+ return data_.record_size;
+ }
+
+ template <typename T = Traits>
+ typename std::enable_if<T::kUseStaticRecordSize, void>::type set_record_size(
+ uint32_t /*record_size*/) {}
+
+ template <typename T = Traits>
+ typename std::enable_if<!T::kUseStaticRecordSize, void>::type set_record_size(
+ uint32_t record_size) {
+ data_.record_size = record_size;
+ }
+
+ template <typename T = Traits>
+ typename std::enable_if<T::kUseStaticRecordCount, uint32_t>::type
+ record_count_internal() const {
+ return Traits::kStaticRecordCount;
+ }
+
+ template <typename T = Traits>
+ typename std::enable_if<!T::kUseStaticRecordCount, uint32_t>::type
+ record_count_internal() const {
+ return data_.record_count;
+ }
+
+ template <typename T = Traits>
+ typename std::enable_if<T::kUseStaticRecordCount, void>::type
+ set_record_count(uint32_t /*record_count*/) const {}
+
+ template <typename T = Traits>
+ typename std::enable_if<!T::kUseStaticRecordCount, void>::type
+ set_record_count(uint32_t record_count) {
+ data_.record_count = record_count;
+ }
+
+ // Data we need to store for statically sized rings.
+ struct DataStaticSize {
+ Mmap* mmap = nullptr;
+ };
+
+ // Data we need to store for dynamically sized rings.
+ struct DataDynamicSize {
+ Mmap* mmap = nullptr;
+
+ // These are cached to make sure misbehaving writers cannot cause
+ // out-of-bounds memory accesses by updating the values in the mmap header.
+ uint32_t record_size = 0;
+ uint32_t record_count = 0;
+ };
+
+ using DataStaticOrDynamic =
+ typename std::conditional<Traits::kIsStaticSize, DataStaticSize,
+ DataDynamicSize>::type;
+
+ DataStaticOrDynamic data_;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_BROADCAST_RING_H_
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index b91de8f..5dc4a1b 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -109,6 +109,11 @@
dvr_api->hwc_frame_get_display_width = dvrHwcFrameGetDisplayWidth;
dvr_api->hwc_frame_get_display_height = dvrHwcFrameGetDisplayHeight;
dvr_api->hwc_frame_get_display_removed = dvrHwcFrameGetDisplayRemoved;
+ dvr_api->hwc_frame_get_active_config = dvrHwcFrameGetActiveConfig;
+ dvr_api->hwc_frame_get_color_mode = dvrHwcFrameGetColorMode;
+ dvr_api->hwc_frame_get_color_transform = dvrHwcFrameGetColorTransform;
+ dvr_api->hwc_frame_get_power_mode = dvrHwcFrameGetPowerMode;
+ dvr_api->hwc_frame_get_vsync_enabled = dvrHwcFrameGetVsyncEnabled;
dvr_api->hwc_frame_get_layer_count = dvrHwcFrameGetLayerCount;
dvr_api->hwc_frame_get_layer_id = dvrHwcFrameGetLayerId;
dvr_api->hwc_frame_get_layer_buffer = dvrHwcFrameGetLayerBuffer;
@@ -121,6 +126,19 @@
dvr_api->hwc_frame_get_layer_type = dvrHwcFrameGetLayerType;
dvr_api->hwc_frame_get_layer_application_id =
dvrHwcFrameGetLayerApplicationId;
+ dvr_api->hwc_frame_get_layer_z_order = dvrHwcFrameGetLayerZOrder;
+ dvr_api->hwc_frame_get_layer_cursor = dvrHwcFrameGetLayerCursor;
+ dvr_api->hwc_frame_get_layer_transform = dvrHwcFrameGetLayerTransform;
+ dvr_api->hwc_frame_get_layer_dataspace = dvrHwcFrameGetLayerDataspace;
+ dvr_api->hwc_frame_get_layer_color = dvrHwcFrameGetLayerColor;
+ dvr_api->hwc_frame_get_layer_num_visible_regions =
+ dvrHwcFrameGetLayerNumVisibleRegions;
+ dvr_api->hwc_frame_get_layer_visible_region =
+ dvrHwcFrameGetLayerVisibleRegion;
+ dvr_api->hwc_frame_get_layer_num_damaged_regions =
+ dvrHwcFrameGetLayerNumDamagedRegions;
+ dvr_api->hwc_frame_get_layer_damaged_region =
+ dvrHwcFrameGetLayerDamagedRegion;
return 0;
}
diff --git a/libs/vr/libdvr/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
index 39c2a90..d3ae299 100644
--- a/libs/vr/libdvr/dvr_hardware_composer_client.cpp
+++ b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
@@ -104,6 +104,29 @@
return frame->frame.layers.size();
}
+uint32_t dvrHwcFrameGetActiveConfig(DvrHwcFrame* frame) {
+ return static_cast<uint32_t>(frame->frame.active_config);
+}
+
+uint32_t dvrHwcFrameGetColorMode(DvrHwcFrame* frame) {
+ return static_cast<uint32_t>(frame->frame.color_mode);
+}
+
+void dvrHwcFrameGetColorTransform(DvrHwcFrame* frame, float* out_matrix,
+ int32_t* out_hint) {
+ *out_hint = frame->frame.color_transform_hint;
+ memcpy(out_matrix, frame->frame.color_transform,
+ sizeof(frame->frame.color_transform));
+}
+
+uint32_t dvrHwcFrameGetPowerMode(DvrHwcFrame* frame) {
+ return static_cast<uint32_t>(frame->frame.power_mode);
+}
+
+uint32_t dvrHwcFrameGetVsyncEnabled(DvrHwcFrame* frame) {
+ return static_cast<uint32_t>(frame->frame.vsync_enabled);
+}
+
DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index) {
return frame->frame.layers[layer_index].id;
}
@@ -157,3 +180,58 @@
size_t layer_index) {
return frame->frame.layers[layer_index].app_id;
}
+
+uint32_t dvrHwcFrameGetLayerZOrder(DvrHwcFrame* frame, size_t layer_index) {
+ return frame->frame.layers[layer_index].z_order;
+}
+
+void dvrHwcFrameGetLayerCursor(DvrHwcFrame* frame, size_t layer_index,
+ int32_t* out_x, int32_t* out_y) {
+ *out_x = frame->frame.layers[layer_index].cursor_x;
+ *out_y = frame->frame.layers[layer_index].cursor_y;
+}
+
+uint32_t dvrHwcFrameGetLayerTransform(DvrHwcFrame* frame, size_t layer_index) {
+ return frame->frame.layers[layer_index].transform;
+}
+
+uint32_t dvrHwcFrameGetLayerDataspace(DvrHwcFrame* frame, size_t layer_index) {
+ return frame->frame.layers[layer_index].dataspace;
+}
+
+uint32_t dvrHwcFrameGetLayerColor(DvrHwcFrame* frame, size_t layer_index) {
+ const auto& color = frame->frame.layers[layer_index].color;
+ return color.r | (static_cast<uint32_t>(color.g) << 8) |
+ (static_cast<uint32_t>(color.b) << 16) |
+ (static_cast<uint32_t>(color.a) << 24);
+}
+
+uint32_t dvrHwcFrameGetLayerNumVisibleRegions(DvrHwcFrame* frame,
+ size_t layer_index) {
+ return frame->frame.layers[layer_index].visible_regions.size();
+}
+
+DvrHwcRecti dvrHwcFrameGetLayerVisibleRegion(DvrHwcFrame* frame,
+ size_t layer_index, size_t index) {
+ return DvrHwcRecti{
+ frame->frame.layers[layer_index].visible_regions[index].left,
+ frame->frame.layers[layer_index].visible_regions[index].top,
+ frame->frame.layers[layer_index].visible_regions[index].right,
+ frame->frame.layers[layer_index].visible_regions[index].bottom,
+ };
+}
+
+uint32_t dvrHwcFrameGetLayerNumDamagedRegions(DvrHwcFrame* frame,
+ size_t layer_index) {
+ return frame->frame.layers[layer_index].damaged_regions.size();
+}
+
+DvrHwcRecti dvrHwcFrameGetLayerDamagedRegion(DvrHwcFrame* frame,
+ size_t layer_index, size_t index) {
+ return DvrHwcRecti{
+ frame->frame.layers[layer_index].damaged_regions[index].left,
+ frame->frame.layers[layer_index].damaged_regions[index].top,
+ frame->frame.layers[layer_index].damaged_regions[index].right,
+ frame->frame.layers[layer_index].damaged_regions[index].bottom,
+ };
+}
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 7dc6a30..a69433d 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -159,6 +159,13 @@
typedef size_t (*DvrHwcFrameGetLayerCountPtr)(DvrHwcFrame* frame);
typedef DvrHwcLayer (*DvrHwcFrameGetLayerIdPtr)(DvrHwcFrame* frame,
size_t layer_index);
+typedef uint32_t (*DvrHwcFrameGetActiveConfigPtr)(DvrHwcFrame* frame);
+typedef uint32_t (*DvrHwcFrameGetColorModePtr)(DvrHwcFrame* frame);
+typedef void (*DvrHwcFrameGetColorTransformPtr)(DvrHwcFrame* frame,
+ float* out_matrix,
+ int32_t* out_hint);
+typedef uint32_t (*DvrHwcFrameGetPowerModePtr)(DvrHwcFrame* frame);
+typedef uint32_t (*DvrHwcFrameGetVsyncEnabledPtr)(DvrHwcFrame* frame);
typedef AHardwareBuffer* (*DvrHwcFrameGetLayerBufferPtr)(DvrHwcFrame* frame,
size_t layer_index);
typedef int (*DvrHwcFrameGetLayerFencePtr)(DvrHwcFrame* frame,
@@ -175,6 +182,33 @@
size_t layer_index);
typedef uint32_t (*DvrHwcFrameGetLayerApplicationIdPtr)(DvrHwcFrame* frame,
size_t layer_index);
+typedef uint32_t (*DvrHwcFrameGetLayerZOrderPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+
+typedef void (*DvrHwcFrameGetLayerCursorPtr)(DvrHwcFrame* frame,
+ size_t layer_index, int32_t* out_x,
+ int32_t* out_y);
+
+typedef uint32_t (*DvrHwcFrameGetLayerTransformPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+
+typedef uint32_t (*DvrHwcFrameGetLayerDataspacePtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+
+typedef uint32_t (*DvrHwcFrameGetLayerColorPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+
+typedef uint32_t (*DvrHwcFrameGetLayerNumVisibleRegionsPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef DvrHwcRecti (*DvrHwcFrameGetLayerVisibleRegionPtr)(DvrHwcFrame* frame,
+ size_t layer_index,
+ size_t index);
+
+typedef uint32_t (*DvrHwcFrameGetLayerNumDamagedRegionsPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef DvrHwcRecti (*DvrHwcFrameGetLayerDamagedRegionPtr)(DvrHwcFrame* frame,
+ size_t layer_index,
+ size_t index);
struct DvrApi_v1 {
// Display manager client
@@ -261,6 +295,11 @@
DvrHwcFrameGetDisplayWidthPtr hwc_frame_get_display_width;
DvrHwcFrameGetDisplayHeightPtr hwc_frame_get_display_height;
DvrHwcFrameGetDisplayRemovedPtr hwc_frame_get_display_removed;
+ DvrHwcFrameGetActiveConfigPtr hwc_frame_get_active_config;
+ DvrHwcFrameGetColorModePtr hwc_frame_get_color_mode;
+ DvrHwcFrameGetColorTransformPtr hwc_frame_get_color_transform;
+ DvrHwcFrameGetPowerModePtr hwc_frame_get_power_mode;
+ DvrHwcFrameGetVsyncEnabledPtr hwc_frame_get_vsync_enabled;
DvrHwcFrameGetLayerCountPtr hwc_frame_get_layer_count;
DvrHwcFrameGetLayerIdPtr hwc_frame_get_layer_id;
DvrHwcFrameGetLayerBufferPtr hwc_frame_get_layer_buffer;
@@ -271,6 +310,17 @@
DvrHwcFrameGetLayerAlphaPtr hwc_frame_get_layer_alpha;
DvrHwcFrameGetLayerTypePtr hwc_frame_get_layer_type;
DvrHwcFrameGetLayerApplicationIdPtr hwc_frame_get_layer_application_id;
+ DvrHwcFrameGetLayerZOrderPtr hwc_frame_get_layer_z_order;
+ DvrHwcFrameGetLayerCursorPtr hwc_frame_get_layer_cursor;
+ DvrHwcFrameGetLayerTransformPtr hwc_frame_get_layer_transform;
+ DvrHwcFrameGetLayerDataspacePtr hwc_frame_get_layer_dataspace;
+ DvrHwcFrameGetLayerColorPtr hwc_frame_get_layer_color;
+ DvrHwcFrameGetLayerNumVisibleRegionsPtr
+ hwc_frame_get_layer_num_visible_regions;
+ DvrHwcFrameGetLayerVisibleRegionPtr hwc_frame_get_layer_visible_region;
+ DvrHwcFrameGetLayerNumDamagedRegionsPtr
+ hwc_frame_get_layer_num_damaged_regions;
+ DvrHwcFrameGetLayerDamagedRegionPtr hwc_frame_get_layer_damaged_region;
};
int dvrGetApi(void* api, size_t struct_size, int version);
diff --git a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
index 2d28aa3..7ee7f9e 100644
--- a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
@@ -43,6 +43,13 @@
// @return Number of layers in the frame.
size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame);
+uint32_t dvrHwcFrameGetActiveConfig(DvrHwcFrame* frame);
+uint32_t dvrHwcFrameGetColorMode(DvrHwcFrame* frame);
+void dvrHwcFrameGetColorTransform(DvrHwcFrame* frame, float* out_matrix,
+ int32_t* out_hint);
+uint32_t dvrHwcFrameGetPowerMode(DvrHwcFrame* frame);
+uint32_t dvrHwcFrameGetVsyncEnabled(DvrHwcFrame* frame);
+
DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index);
// Return the graphic buffer associated with the layer at |layer_index| in
@@ -73,6 +80,26 @@
uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
size_t layer_index);
+uint32_t dvrHwcFrameGetLayerZOrder(DvrHwcFrame* frame, size_t layer_index);
+
+void dvrHwcFrameGetLayerCursor(DvrHwcFrame* frame, size_t layer_index,
+ int32_t* out_x, int32_t* out_y);
+
+uint32_t dvrHwcFrameGetLayerTransform(DvrHwcFrame* frame, size_t layer_index);
+
+uint32_t dvrHwcFrameGetLayerDataspace(DvrHwcFrame* frame, size_t layer_index);
+
+uint32_t dvrHwcFrameGetLayerColor(DvrHwcFrame* frame, size_t layer_index);
+
+uint32_t dvrHwcFrameGetLayerNumVisibleRegions(DvrHwcFrame* frame,
+ size_t layer_index);
+DvrHwcRecti dvrHwcFrameGetLayerVisibleRegion(DvrHwcFrame* frame,
+ size_t layer_index, size_t index);
+
+uint32_t dvrHwcFrameGetLayerNumDamagedRegions(DvrHwcFrame* frame,
+ size_t layer_index);
+DvrHwcRecti dvrHwcFrameGetLayerDamagedRegion(DvrHwcFrame* frame,
+ size_t layer_index, size_t index);
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libs/vr/libeds/Android.bp b/libs/vr/libeds/Android.bp
index 187cbbf..85e43cc 100644
--- a/libs/vr/libeds/Android.bp
+++ b/libs/vr/libeds/Android.bp
@@ -16,11 +16,9 @@
"eds.cpp",
"eds_mesh.cpp",
"composite_hmd.cpp",
- "cpu_thread_pose_updater.cpp",
"display_metrics.cpp",
"distortion_renderer.cpp",
- "lucid_metrics.cpp",
- "lucid_pose_tracker.cpp",
+ "device_metrics.cpp",
"lookup_radial_distortion.cpp",
"polynomial_radial_distortion.cpp",
]
diff --git a/libs/vr/libeds/cpu_thread_pose_updater.cpp b/libs/vr/libeds/cpu_thread_pose_updater.cpp
deleted file mode 100644
index 5b8a734..0000000
--- a/libs/vr/libeds/cpu_thread_pose_updater.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "include/private/dvr/cpu_thread_pose_updater.h"
-
-#include <sys/prctl.h>
-#include <unistd.h>
-
-#define ATRACE_TAG ATRACE_TAG_INPUT
-#include <utils/Trace.h>
-
-#include <private/dvr/clock_ns.h>
-#include <private/dvr/debug.h>
-
-namespace android {
-namespace dvr {
-
-CpuThreadPoseUpdater::CpuThreadPoseUpdater()
- : stop_request_(false), update_period_us_(0), count_(0) {}
-
-CpuThreadPoseUpdater::~CpuThreadPoseUpdater() { StopAndJoin(); }
-
-void CpuThreadPoseUpdater::Start(volatile RawPosePair* mapped_pose_buffer,
- int period_us) {
- mapped_pose_buffer_ = mapped_pose_buffer;
- update_period_us_ = period_us;
- stop_request_ = false;
-
- // First buffer is odd (starts at 1), second is even (starts at 2).
- count_ = 0;
- mapped_pose_buffer_->pose1.Reset(++count_);
- mapped_pose_buffer_->pose2.Reset(++count_);
-
- update_thread_ = std::thread(&CpuThreadPoseUpdater::UpdateThread, this);
-}
-
-void CpuThreadPoseUpdater::StopAndJoin() {
- stop_request_ = true;
- if (update_thread_.joinable()) {
- update_thread_.join();
- }
-}
-
-void CpuThreadPoseUpdater::UpdateThread() {
- prctl(PR_SET_NAME, reinterpret_cast<intptr_t>("CpuPoseUpdater"),
- 0, 0, 0);
-
- ATRACE_NAME(__PRETTY_FUNCTION__);
- for (;;) {
- if (stop_request_) {
- break;
- }
-
- ++count_;
-
- // Choose the writable pose based on whether count is odd or even.
- volatile RawPose* out_pose = nullptr;
- if (count_ & 1) {
- out_pose = &mapped_pose_buffer_->pose1;
- } else {
- out_pose = &mapped_pose_buffer_->pose2;
- }
-
- {
- ATRACE_NAME("GetPose");
- Posef pose = pose_tracker_.GetPose(GetSystemClockNs());
- out_pose->qx = pose.GetRotation().x();
- out_pose->qy = pose.GetRotation().y();
- out_pose->qz = pose.GetRotation().z();
- out_pose->qw = pose.GetRotation().w();
- out_pose->px = pose.GetPosition()[0];
- out_pose->py = pose.GetPosition()[1];
- out_pose->pz = pose.GetPosition()[2];
- // Atomically store the count so that it hits memory last:
- out_pose->count.store(count_, std::memory_order_release);
- }
-
- // Sleep to simulate the IMU update process.
- usleep(update_period_us_);
- // TODO(jbates) sleep_for returns immediately, we need to fix our toolchain!
- // int64_t c1 = GetSystemClockNs();
- // std::this_thread::sleep_for(std::chrono::milliseconds(10));
- // int64_t c2 = GetSystemClockNs();
- // fprintf(stderr, "%lld us\n", (long long)(c2 - c1) / 1000);
- }
-}
-
-} // namesapce dvr
-} // namesapce android
diff --git a/libs/vr/libeds/device_metrics.cpp b/libs/vr/libeds/device_metrics.cpp
new file mode 100644
index 0000000..50c3e54
--- /dev/null
+++ b/libs/vr/libeds/device_metrics.cpp
@@ -0,0 +1,182 @@
+#include <private/dvr/device_metrics.h>
+
+#include <cutils/properties.h>
+#include <private/dvr/head_mount_metrics.h>
+#include <private/dvr/identity_distortion.h>
+#include <private/dvr/lookup_radial_distortion.h>
+#include <private/dvr/polynomial_radial_distortion.h>
+#include <private/dvr/types.h>
+#include "include/private/dvr/display_metrics.h"
+
+namespace {
+
+static constexpr char kRGBPolynomialOffset[] = "persist.dvr.rgb_poly_offset";
+static constexpr char kRPolynomial[] = "persist.dvr.r_poly";
+static constexpr char kGPolynomial[] = "persist.dvr.g_poly";
+static constexpr char kBPolynomial[] = "persist.dvr.b_poly";
+static constexpr char kLensDistance[] = "persist.dvr.lens_distance";
+static constexpr char kDisplayGap[] = "persist.dvr.display_gap";
+static constexpr char kVEyeToDisplay[] = "persist.dvr.v_eye_to_display";
+static constexpr char kFovIOBT[] = "persist.dvr.fov_iobt";
+static constexpr char kScreenSize[] = "persist.dvr.screen_size";
+
+bool StringToFloat(const char* str, float* result) {
+ char* endptr = nullptr;
+ *result = std::strtof(str, &endptr);
+ return !(str == endptr || !endptr);
+}
+
+std::vector<std::string> SplitString(const std::string& string_to_split,
+ char deliminator) {
+ std::vector<std::string> result;
+ std::string sub_string;
+ std::stringstream ss(string_to_split);
+ while (std::getline(ss, sub_string, deliminator))
+ result.push_back(sub_string);
+ return result;
+}
+
+std::vector<float> GetProperty(const char* name,
+ const std::vector<float>& default_values) {
+ char prop[PROPERTY_VALUE_MAX + 1] = {};
+ property_get(name, prop, "");
+ std::vector<std::string> values = SplitString(prop, ',');
+ std::vector<float> results;
+ for (const auto& value : values) {
+ float result = 0.0f;
+ if (StringToFloat(value.c_str(), &result)) {
+ results.push_back(static_cast<float>(result));
+ }
+ }
+ if (results.empty()) {
+ return default_values;
+ }
+ return results;
+}
+
+float GetProperty(const char* name, float default_value) {
+ char prop[PROPERTY_VALUE_MAX + 1] = {};
+ property_get(name, prop, "");
+ float result = 0.0f;
+ if (StringToFloat(prop, &result)) {
+ return static_cast<float>(result);
+ }
+ return default_value;
+}
+
+float GetInterLensDistance() { return GetProperty(kLensDistance, 0.064f); }
+
+float GetDisplayGap() { return GetProperty(kDisplayGap, 0.0f); }
+
+float GetVEyeToDisplay() { return GetProperty(kVEyeToDisplay, 0.035f); }
+
+android::dvr::vec2 GetDisplaySize() {
+ static const std::vector<float> default_size = {0.0742177f, 0.131943f};
+ std::vector<float> sizes = GetProperty(kScreenSize, default_size);
+ if (sizes.size() != 0)
+ sizes = default_size;
+ return android::dvr::vec2(sizes[0], sizes[1]);
+}
+
+std::vector<float> GetMaxFOVs() {
+ static const std::vector<float> defaults = {43.7f, 47.8f, 54.2f, 54.2f};
+ std::vector<float> fovs = GetProperty(kFovIOBT, defaults);
+ if (fovs.size() != 4)
+ fovs = defaults;
+ for (auto& value : fovs) {
+ value = value * M_PI / 180.0f;
+ }
+ return fovs;
+}
+
+static const android::dvr::HeadMountMetrics::VerticalAlignment
+ kDefaultVerticalAlignment = android::dvr::HeadMountMetrics::kCenter;
+
+// Default border size in meters.
+static const float kScreenBorderSize = 0.004f;
+
+// Refresh rate.
+static const float kScreenRefreshRate = 60.0f;
+
+// Default display orientation is portrait.
+static const android::dvr::DisplayOrientation kDisplayOrientation =
+ android::dvr::DisplayOrientation::kPortrait;
+
+} // anonymous namespace
+
+namespace android {
+namespace dvr {
+
+HeadMountMetrics CreateHeadMountMetrics(const FieldOfView& l_fov,
+ const FieldOfView& r_fov) {
+ static const std::vector<float> default_r = {
+ -4.08519004f, 34.70282075f, -67.37781249f, 56.97304235f,
+ -23.35768685f, 4.7199597f, 0.63198082f};
+ static const std::vector<float> default_g = {
+ 4.43078318f, 3.47806617f, -20.58017398f, 20.85880414f,
+ -8.4046504f, 1.61284685f, 0.8881761f};
+ static const std::vector<float> default_b = {
+ 12.04141265f, -21.98112491f, 14.06758389f, -3.15245629f,
+ 0.36549102f, 0.05252705f, 0.99844279f};
+ static const std::vector<float> default_offsets = {
+ 0.20971645238f, 0.15189450000f, 1.00096958278f};
+
+ std::vector<float> poly_offsets =
+ GetProperty(kRGBPolynomialOffset, default_offsets);
+ std::vector<float> poly_r = GetProperty(kRPolynomial, default_r);
+ std::vector<float> poly_g = GetProperty(kGPolynomial, default_g);
+ std::vector<float> poly_b = GetProperty(kBPolynomial, default_b);
+ if (poly_offsets.size() != 3)
+ poly_offsets = default_offsets;
+
+ std::shared_ptr<ColorChannelDistortion> distortion_r(
+ new PolynomialRadialDistortion(poly_offsets[0], poly_r));
+ std::shared_ptr<ColorChannelDistortion> distortion_g(
+ new PolynomialRadialDistortion(poly_offsets[1], poly_g));
+ std::shared_ptr<ColorChannelDistortion> distortion_b(
+ new PolynomialRadialDistortion(poly_offsets[2], poly_b));
+
+ return HeadMountMetrics(GetInterLensDistance(), GetVEyeToDisplay(),
+ GetVEyeToDisplay(), kDefaultVerticalAlignment, l_fov,
+ r_fov, distortion_r, distortion_g, distortion_b,
+ HeadMountMetrics::EyeOrientation::kCCW0Degrees,
+ HeadMountMetrics::EyeOrientation::kCCW0Degrees,
+ (GetInterLensDistance() - GetDisplayGap()) / 2.0f);
+}
+
+HeadMountMetrics CreateHeadMountMetrics() {
+ std::vector<float> fovs = GetMaxFOVs();
+ FieldOfView l_fov(fovs[1], fovs[0], fovs[2], fovs[3]);
+ FieldOfView r_fov(fovs[0], fovs[1], fovs[2], fovs[3]);
+ return CreateHeadMountMetrics(l_fov, r_fov);
+}
+
+DisplayMetrics CreateDisplayMetrics(vec2i screen_size) {
+ android::dvr::vec2 size_in_meters = GetDisplaySize();
+ vec2 meters_per_pixel(size_in_meters[0] / static_cast<float>(screen_size[0]),
+ size_in_meters[1] / static_cast<float>(screen_size[1]));
+ return DisplayMetrics(screen_size, meters_per_pixel, kScreenBorderSize,
+ 1000.0f / kScreenRefreshRate, kDisplayOrientation);
+}
+
+HeadMountMetrics CreateUndistortedHeadMountMetrics() {
+ std::vector<float> fovs = GetMaxFOVs();
+ FieldOfView l_fov(fovs[1], fovs[0], fovs[2], fovs[3]);
+ FieldOfView r_fov(fovs[0], fovs[1], fovs[2], fovs[3]);
+ return CreateUndistortedHeadMountMetrics(l_fov, r_fov);
+}
+
+HeadMountMetrics CreateUndistortedHeadMountMetrics(const FieldOfView& l_fov,
+ const FieldOfView& r_fov) {
+ auto distortion_all = std::make_shared<IdentityDistortion>();
+
+ return HeadMountMetrics(GetInterLensDistance(), GetVEyeToDisplay(),
+ GetVEyeToDisplay(), kDefaultVerticalAlignment, l_fov,
+ r_fov, distortion_all, distortion_all, distortion_all,
+ HeadMountMetrics::EyeOrientation::kCCW0Degrees,
+ HeadMountMetrics::EyeOrientation::kCCW0Degrees,
+ (GetInterLensDistance() - GetDisplayGap()) / 2.0f);
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libeds/include/private/dvr/cpu_thread_pose_updater.h b/libs/vr/libeds/include/private/dvr/cpu_thread_pose_updater.h
deleted file mode 100644
index 6a2c8a6..0000000
--- a/libs/vr/libeds/include/private/dvr/cpu_thread_pose_updater.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef ANDROID_DVR_CPU_THREAD_POSE_UPDATER_H_
-#define ANDROID_DVR_CPU_THREAD_POSE_UPDATER_H_
-
-#include <atomic>
-#include <thread>
-
-#include <private/dvr/lucid_pose_tracker.h>
-#include <private/dvr/raw_pose.h>
-
-namespace android {
-namespace dvr {
-
-// Temporary version of pose updater that uses a CPU thread to update
-// the pose buffer. Note that this thread starts and runs indefinitely
-class CpuThreadPoseUpdater {
- public:
- CpuThreadPoseUpdater();
- ~CpuThreadPoseUpdater();
-
- // Start the thread to update the given buffer with the given number of
- // microseconds between updates.
- void Start(volatile RawPosePair* mapped_pose_buffer, int period_us);
-
- void StopAndJoin();
-
- private:
- void UpdateThread();
-
- volatile RawPosePair* mapped_pose_buffer_;
-
- // Pose update thread.
- std::thread update_thread_;
-
- volatile bool stop_request_;
-
- // Update period in microseconds.
- int update_period_us_;
-
- // Current pose count, used to avoid writing to the same buffer that is being
- // read by the GPU.
- uint32_t count_;
- LucidPoseTracker pose_tracker_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_CPU_THREAD_POSE_UPDATER_H_
diff --git a/libs/vr/libeds/include/private/dvr/lucid_metrics.h b/libs/vr/libeds/include/private/dvr/device_metrics.h
similarity index 84%
rename from libs/vr/libeds/include/private/dvr/lucid_metrics.h
rename to libs/vr/libeds/include/private/dvr/device_metrics.h
index 0e4ada4..7985f28 100644
--- a/libs/vr/libeds/include/private/dvr/lucid_metrics.h
+++ b/libs/vr/libeds/include/private/dvr/device_metrics.h
@@ -1,5 +1,5 @@
-#ifndef ANDROID_DVR_LUCID_METRICS_H_
-#define ANDROID_DVR_LUCID_METRICS_H_
+#ifndef ANDROID_DVR_DEVICE_METRICS_H_
+#define ANDROID_DVR_DEVICE_METRICS_H_
#include <private/dvr/display_metrics.h>
#include <private/dvr/head_mount_metrics.h>
@@ -19,4 +19,4 @@
} // namespace dvr
} // namespace android
-#endif // ANDROID_DVR_LUCID_METRICS_H_
+#endif // ANDROID_DVR_DEVICE_METRICS_H_
diff --git a/libs/vr/libeds/include/private/dvr/distortion_renderer.h b/libs/vr/libeds/include/private/dvr/distortion_renderer.h
index e1c8114..28fd48a 100644
--- a/libs/vr/libeds/include/private/dvr/distortion_renderer.h
+++ b/libs/vr/libeds/include/private/dvr/distortion_renderer.h
@@ -9,7 +9,6 @@
#include <private/dvr/eds_mesh.h>
#include <private/dvr/graphics/shader_program.h>
#include <private/dvr/late_latch.h>
-#include <private/dvr/lucid_pose_tracker.h>
#include <private/dvr/render_texture_params.h>
#include <private/dvr/types.h>
diff --git a/libs/vr/libeds/include/private/dvr/lucid_pose_tracker.h b/libs/vr/libeds/include/private/dvr/lucid_pose_tracker.h
deleted file mode 100644
index 4ceda5a..0000000
--- a/libs/vr/libeds/include/private/dvr/lucid_pose_tracker.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef ANDROID_DVR_LUCID_POSE_TRACKER_H_
-#define ANDROID_DVR_LUCID_POSE_TRACKER_H_
-
-#include <memory>
-
-#include <dvr/pose_client.h>
-
-#include <private/dvr/types.h>
-
-namespace android {
-namespace dvr {
-
-// Provides pose tracking via the system pose service.
-class LucidPoseTracker {
- public:
- // When set, the pose service is ignored and the given pose is always returned
- // by GetPose. As long as this is called before any LucidPoseTracker is
- // used, the pose service will not be created.
- // Threading: this is not thread safe.
- static void SetPoseOverride(const Posef& pose);
-
- // Reset prior override pose.
- static void ClearPoseOverride();
-
- LucidPoseTracker();
- ~LucidPoseTracker();
-
- // Currently GetPose() will ignore timestamp_ns and always return the most
- // recent orientation.
- // TODO(stefanus): support prediction.
- Posef GetPose(uint64_t timestamp_ns);
-
- private:
- static bool is_override_pose_;
- static Posef override_pose_;
-
- DvrPose* pose_client_;
-
- // The most recent pose.
- Posef latest_pose_;
-
- // The time stamp corresponding to when latest_pose_ was last updated.
- uint64_t latest_timestamp_ns_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_LUCID_POSE_TRACKER_H_
diff --git a/libs/vr/libeds/include/private/dvr/polynomial_radial_distortion.h b/libs/vr/libeds/include/private/dvr/polynomial_radial_distortion.h
index 8f080aa..c1f1ce9 100644
--- a/libs/vr/libeds/include/private/dvr/polynomial_radial_distortion.h
+++ b/libs/vr/libeds/include/private/dvr/polynomial_radial_distortion.h
@@ -28,7 +28,8 @@
// in the distortion equation: coefficients[0] is K1, coefficients[1] is K2,
// etc. Thus the polynomial used for distortion has degree
// (2 * coefficients.size()).
- explicit PolynomialRadialDistortion(const std::vector<float>& coefficients);
+ explicit PolynomialRadialDistortion(float polynomial_offset,
+ const std::vector<float>& coefficients);
// Given a radius (measuring distance from the optical axis of the lens),
// returns the distortion factor for that radius.
@@ -51,6 +52,10 @@
const std::vector<float>& GetCoefficients() const;
private:
+ // This is makes the polynomial work nicer with a specific lens that doesn't
+ // fit nicely to a lower order polynomial. It's basically piecewise
+ // line->poly.
+ float polynomial_offset_;
std::vector<float> coefficients_;
};
diff --git a/libs/vr/libeds/lucid_metrics.cpp b/libs/vr/libeds/lucid_metrics.cpp
deleted file mode 100644
index 690c326..0000000
--- a/libs/vr/libeds/lucid_metrics.cpp
+++ /dev/null
@@ -1,327 +0,0 @@
-#include "include/private/dvr/display_metrics.h"
-#include <private/dvr/head_mount_metrics.h>
-#include <private/dvr/identity_distortion.h>
-#include <private/dvr/lookup_radial_distortion.h>
-#include <private/dvr/lucid_metrics.h>
-#include <private/dvr/types.h>
-
-namespace {
-
-// These numbers are specific to the OnePlus One and therefore
-// temporary until we advance to the next Lucid development platform.
-
-// Head mount metrics for Lucid A00
-static const float kDefaultInterLensDistance = 0.064f; // 64mm
-static const float kDefaultTrayToLensDistance = 0.035f;
-static const float kDefaultVirtualEyeToScreenDistance = 0.042f;
-static const android::dvr::HeadMountMetrics::VerticalAlignment
- kDefaultVerticalAlignment = android::dvr::HeadMountMetrics::kCenter;
-static const float kDefaultFovHalfAngleInsideH = 43.7f * M_PI / 180.0f;
-static const float kDefaultFovHalfAngleOutsideH = 47.8f * M_PI / 180.0f;
-static const float kDefaultFovHalfAngleV = 54.2f * M_PI / 180.0f;
-
-// Screen size in meters for Lucid (Nexus 6 display in portrait mode).
-static const android::dvr::vec2 kScreenSizeInMeters(0.0742177f, 0.131943f);
-
-// Border size in meters for the OnePlus One.
-static const float kScreenBorderSize = 0.004f;
-
-// Refresh rate.
-static const float kScreenRefreshRate = 60.0f;
-
-// Lucid display orientation is portrait.
-static const android::dvr::DisplayOrientation kDisplayOrientation =
- android::dvr::DisplayOrientation::kPortrait;
-
-} // anonymous namespace
-
-namespace android {
-namespace dvr {
-
-// The distortion lookup tables were generated via a raytraced lens simulation.
-// Please see for full calculations:
-// https://docs.google.com/a/google.com/spreadsheets/d/
-// 15cfHmCw5mHVOQ1rAJxMhta4q0e8zzcUDka1nRkfl7pY/edit?usp=sharing
-LookupRadialDistortion* GetBlueDistortionLookup() {
- // clang-format off
- vec2 kBlueDistortionLookup[] = {
- {0.00000000000f, 1.00000000000f},
- {0.01888626190f, 1.00096958278f},
- {0.03777223810f, 1.00133301793f},
- {0.05665761905f, 1.00193985168f},
- {0.07554214286f, 1.00279048731f},
- {0.09442542857f, 1.00388751781f},
- {0.11330704762f, 1.00523363045f},
- {0.13218657143f, 1.00683149424f},
- {0.15106340476f, 1.00868516849f},
- {0.16993695238f, 1.01079861126f},
- {0.18880640476f, 1.01317712726f},
- {0.20767092857f, 1.01582607321f},
- {0.22652945238f, 1.01875203063f},
- {0.24538078571f, 1.02196207850f},
- {0.26422352381f, 1.02546421601f},
- {0.28305602381f, 1.02926737969f},
- {0.30187640476f, 1.03338139216f},
- {0.32068252381f, 1.03781702504f},
- {0.33947190476f, 1.04258620905f},
- {0.35824171429f, 1.04770206653f},
- {0.37698869048f, 1.05317909331f},
- {0.39570916667f, 1.05903306635f},
- {0.41439900000f, 1.06528124790f},
- {0.43305350000f, 1.07194257391f},
- {0.45166738095f, 1.07903777957f},
- {0.47023471429f, 1.08658953759f},
- {0.48874897619f, 1.09462239798f},
- {0.50720285714f, 1.10316330018f},
- {0.52558835714f, 1.11224144183f},
- {0.54389669048f, 1.12188861421f},
- {0.56211826190f, 1.13213939967f},
- {0.58024261905f, 1.14303145047f},
- {0.59825847619f, 1.15460566091f},
- {0.61615335714f, 1.16690711338f},
- {0.63391345238f, 1.17998560444f},
- {0.65152300000f, 1.19389708987f},
- {0.66896328571f, 1.20870580446f},
- {0.68621100000f, 1.22448751087f},
- {0.70323578571f, 1.24133415620f},
- {0.71999716667f, 1.25935962776f},
- {0.73643969048f, 1.27870875648f},
- {0.75250778571f, 1.29953256670f},
- {0.76817614286f, 1.32193822000f},
- {0.78342009524f, 1.34604270338f},
- {0.79828314286f, 1.37185833833f},
- {0.81267376190f, 1.39964322604f},
- {0.82656559524f, 1.42955958262f},
- {0.83983054762f, 1.46196539657f},
- {0.85234333333f, 1.49724142650f},
- {0.86394971429f, 1.53585530271f},
- {0.87422461905f, 1.57881139444f},
- {0.88382583095f, 1.62091537826f},
- {0.89571361286f, 1.67610209261f},
- {0.90490389167f, 1.72118819668f},
- {0.91526452143f, 1.77496904481f},
- {0.92651365452f, 1.83722833673f},
- {0.93437489976f, 1.88337590145f},
- {0.94654105500f, 1.95937892848f},
- {0.95476685095f, 2.01469745492f},
- {0.96720383310f, 2.10451495481f},
- {0.97546726405f, 2.16904926656f},
- {0.98774046786f, 2.27302748020f},
- {0.99579206762f, 2.34720582421f},
- {1.00763328857f, 2.46603526105f},
- {1.01533118405f, 2.55049232288f},
- {1.02287120929f, 2.63936582235f}
- };
- // clang-format on
- return new LookupRadialDistortion(
- kBlueDistortionLookup, sizeof(kBlueDistortionLookup) / sizeof(vec2));
-}
-
-LookupRadialDistortion* GetGreenDistortionLookup() {
- // clang-format off
- vec2 kGreenDistortionLookup[] = {
- {0.00000000000f, 1.00000000000f},
- {0.01898883333f, 1.00000000000f},
- {0.03797750000f, 1.00000000000f},
- {0.05696585714f, 1.00000000000f},
- {0.07595369048f, 1.00000000000f},
- {0.09494078571f, 1.00000000000f},
- {0.11392685714f, 1.00000000000f},
- {0.13291157143f, 1.00000000000f},
- {0.15189450000f, 1.00176560670f},
- {0.17087511905f, 1.00384553961f},
- {0.18985280952f, 1.00618614484f},
- {0.20882680952f, 1.00879302066f},
- {0.22779623810f, 1.01167234096f},
- {0.24675997619f, 1.01483135203f},
- {0.26571680952f, 1.01827767641f},
- {0.28466519048f, 1.02202026825f},
- {0.30360342857f, 1.02606859705f},
- {0.32252950000f, 1.03043334057f},
- {0.34144104762f, 1.03512630376f},
- {0.36033538095f, 1.04016038545f},
- {0.37920942857f, 1.04554970984f},
- {0.39805966667f, 1.05130981266f},
- {0.41688209524f, 1.05745768999f},
- {0.43567214286f, 1.06401204155f},
- {0.45442473810f, 1.07099310305f},
- {0.47313411905f, 1.07842314596f},
- {0.49179388095f, 1.08632639514f},
- {0.51039692857f, 1.09472920992f},
- {0.52893538095f, 1.10366038032f},
- {0.54740061905f, 1.11315113705f},
- {0.56578326190f, 1.12323535769f},
- {0.58407300000f, 1.13395008040f},
- {0.60225871429f, 1.14533547370f},
- {0.62032809524f, 1.15743581542f},
- {0.63826750000f, 1.17030000749f},
- {0.65606135714f, 1.18398295206f},
- {0.67369107143f, 1.19854780583f},
- {0.69113350000f, 1.21406895255f},
- {0.70835842857f, 1.23063670464f},
- {0.72532545238f, 1.24836302903f},
- {0.74197478571f, 1.26739777609f},
- {0.75822164286f, 1.28793886907f},
- {0.77407361905f, 1.31003521318f},
- {0.78948523810f, 1.33383710115f},
- {0.80448471429f, 1.35938255065f},
- {0.81901733333f, 1.38686361242f},
- {0.83305214286f, 1.41644808409f},
- {0.84646438095f, 1.44848277406f},
- {0.85912733333f, 1.48334485259f},
- {0.87088369048f, 1.52149970074f},
- {0.88131250000f, 1.56392750036f},
- {0.89105132929f, 1.60552684742f},
- {0.90312479476f, 1.66002695068f},
- {0.91244067452f, 1.70458805205f},
- {0.92297971714f, 1.75767475825f},
- {0.93440940905f, 1.81916050294f},
- {0.94237194976f, 1.86478635937f},
- {0.95471202405f, 1.93989738862f},
- {0.96305355738f, 1.99457325750f},
- {0.97567372071f, 2.08333293385f},
- {0.98407229071f, 2.14708073108f},
- {0.99653762071f, 2.24981649552f},
- {1.00471276167f, 2.32311751786f},
- {1.01672394000f, 2.44057411530f},
- {1.02452363381f, 2.52407947994f},
- {1.03216732667f, 2.61194301580f}
- };
- // clang-format on
- return new LookupRadialDistortion(
- kGreenDistortionLookup, sizeof(kGreenDistortionLookup) / sizeof(vec2));
-}
-
-LookupRadialDistortion* GetRedDistortionLookup() {
- // clang-format off
- vec2 kRedDistortionLookup[] = {
- {0.00000000000f, 1.00000000000f},
- {0.01906776190f, 1.00000000000f},
- {0.03813547619f, 1.00000000000f},
- {0.05720304762f, 1.00000000000f},
- {0.07627040476f, 1.00000000000f},
- {0.09533740476f, 1.00000000000f},
- {0.11440385714f, 1.00000000000f},
- {0.13346952381f, 1.00000000000f},
- {0.15253409524f, 1.00000000000f},
- {0.17159714286f, 1.00000000000f},
- {0.19065814286f, 1.00053530030f},
- {0.20971645238f, 1.00310924426f},
- {0.22877123810f, 1.00595236192f},
- {0.24782154762f, 1.00907150786f},
- {0.26686623810f, 1.01247435420f},
- {0.28590388095f, 1.01616968529f},
- {0.30493288095f, 1.02016688932f},
- {0.32395133333f, 1.02447646681f},
- {0.34295697619f, 1.02911011406f},
- {0.36194726190f, 1.03408046560f},
- {0.38091921429f, 1.03940151599f},
- {0.39986942857f, 1.04508858434f},
- {0.41879402381f, 1.05115843585f},
- {0.43768857143f, 1.05762946333f},
- {0.45654809524f, 1.06452169646f},
- {0.47536695238f, 1.07185711363f},
- {0.49413888095f, 1.07965956927f},
- {0.51285690476f, 1.08795508025f},
- {0.53151326190f, 1.09677206014f},
- {0.55009952381f, 1.10614118417f},
- {0.56860633333f, 1.11609607621f},
- {0.58702361905f, 1.12667304464f},
- {0.60534028571f, 1.13791190276f},
- {0.62354421429f, 1.14985618930f},
- {0.64162188095f, 1.16255413653f},
- {0.65955780952f, 1.17605992962f},
- {0.67733352381f, 1.19043584317f},
- {0.69492602381f, 1.20575517508f},
- {0.71230514286f, 1.22210708787f},
- {0.72943057143f, 1.23960199799f},
- {0.74623921429f, 1.25839340501f},
- {0.76262400000f, 1.27871385661f},
- {0.77861754762f, 1.30056919119f},
- {0.79415866667f, 1.32413401001f},
- {0.80926385714f, 1.34946540639f},
- {0.82390640476f, 1.37670655635f},
- {0.83805190476f, 1.40602920817f},
- {0.85157807143f, 1.43777181543f},
- {0.86435700000f, 1.47230885729f},
- {0.87622914286f, 1.51010361811f},
- {0.88677650000f, 1.55211817236f},
- {0.89663317738f, 1.59330127207f},
- {0.90883197952f, 1.64729627820f},
- {0.91827594357f, 1.69138814689f},
- {0.92892199405f, 1.74398939784f},
- {0.94047261548f, 1.80490554711f},
- {0.94852659262f, 1.85009630648f},
- {0.96099790167f, 1.92451421938f},
- {0.96945317500f, 1.97863645920f},
- {0.98221554286f, 2.06656418112f},
- {0.99069599476f, 2.12974390154f},
- {1.00331392976f, 2.23149730290f},
- {1.01157138762f, 2.30414058939f},
- {1.02372409452f, 2.42049694265f},
- {1.03162992905f, 2.50318810924f},
- {1.03934762000f, 2.59027212626f}
- };
- // clang-format on
- return new LookupRadialDistortion(
- kRedDistortionLookup, sizeof(kRedDistortionLookup) / sizeof(vec2));
-}
-
-HeadMountMetrics CreateHeadMountMetrics(const FieldOfView& l_fov,
- const FieldOfView& r_fov) {
- std::shared_ptr<ColorChannelDistortion> default_distortion_r(
- GetRedDistortionLookup());
- std::shared_ptr<ColorChannelDistortion> default_distortion_g(
- GetGreenDistortionLookup());
- std::shared_ptr<ColorChannelDistortion> default_distortion_b(
- GetBlueDistortionLookup());
-
- return HeadMountMetrics(
- kDefaultInterLensDistance, kDefaultTrayToLensDistance,
- kDefaultVirtualEyeToScreenDistance, kDefaultVerticalAlignment, l_fov,
- r_fov, default_distortion_r, default_distortion_g, default_distortion_b,
- HeadMountMetrics::EyeOrientation::kCCW0Degrees,
- HeadMountMetrics::EyeOrientation::kCCW0Degrees,
- kDefaultInterLensDistance / 2.0f);
-}
-
-HeadMountMetrics CreateHeadMountMetrics() {
- FieldOfView l_fov(kDefaultFovHalfAngleOutsideH, kDefaultFovHalfAngleInsideH,
- kDefaultFovHalfAngleV, kDefaultFovHalfAngleV);
- FieldOfView r_fov(kDefaultFovHalfAngleInsideH, kDefaultFovHalfAngleOutsideH,
- kDefaultFovHalfAngleV, kDefaultFovHalfAngleV);
-
- return CreateHeadMountMetrics(l_fov, r_fov);
-}
-
-DisplayMetrics CreateDisplayMetrics(vec2i screen_size) {
- vec2 meters_per_pixel(
- kScreenSizeInMeters[0] / static_cast<float>(screen_size[0]),
- kScreenSizeInMeters[1] / static_cast<float>(screen_size[1]));
- return DisplayMetrics(screen_size, meters_per_pixel, kScreenBorderSize,
- 1000.0f / kScreenRefreshRate, kDisplayOrientation);
-}
-
-HeadMountMetrics CreateUndistortedHeadMountMetrics() {
- FieldOfView l_fov(kDefaultFovHalfAngleOutsideH, kDefaultFovHalfAngleInsideH,
- kDefaultFovHalfAngleV, kDefaultFovHalfAngleV);
- FieldOfView r_fov(kDefaultFovHalfAngleInsideH, kDefaultFovHalfAngleOutsideH,
- kDefaultFovHalfAngleV, kDefaultFovHalfAngleV);
- return CreateUndistortedHeadMountMetrics(l_fov, r_fov);
-}
-
-HeadMountMetrics CreateUndistortedHeadMountMetrics(const FieldOfView& l_fov,
- const FieldOfView& r_fov) {
- auto distortion_all = std::make_shared<IdentityDistortion>();
-
- return HeadMountMetrics(kDefaultInterLensDistance, kDefaultTrayToLensDistance,
- kDefaultVirtualEyeToScreenDistance,
- kDefaultVerticalAlignment, l_fov, r_fov,
- distortion_all, distortion_all, distortion_all,
- HeadMountMetrics::EyeOrientation::kCCW0Degrees,
- HeadMountMetrics::EyeOrientation::kCCW0Degrees,
- kDefaultInterLensDistance / 2.0f);
-}
-
-} // namespace dvr
-} // namespace dvr
diff --git a/libs/vr/libeds/lucid_pose_tracker.cpp b/libs/vr/libeds/lucid_pose_tracker.cpp
deleted file mode 100644
index 5247020..0000000
--- a/libs/vr/libeds/lucid_pose_tracker.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "include/private/dvr/lucid_pose_tracker.h"
-
-#define LOG_TAG "LucidPoseTracker"
-#include <log/log.h>
-
-#include <private/dvr/clock_ns.h>
-
-namespace android {
-namespace dvr {
-
-bool LucidPoseTracker::is_override_pose_ = false;
-Posef LucidPoseTracker::override_pose_ = Posef();
-
-void LucidPoseTracker::SetPoseOverride(const Posef& pose) {
- is_override_pose_ = true;
- override_pose_ = pose;
-}
-
-void LucidPoseTracker::ClearPoseOverride() {
- is_override_pose_ = false;
- override_pose_ = Posef();
-}
-
-LucidPoseTracker::LucidPoseTracker() : pose_client_(NULL) {}
-
-LucidPoseTracker::~LucidPoseTracker() {
- if (pose_client_) {
- dvrPoseDestroy(pose_client_);
- }
-}
-
-Posef LucidPoseTracker::GetPose(uint64_t timestamp_ns) {
- if (is_override_pose_) {
- return override_pose_;
- }
-
- if (!pose_client_) {
- pose_client_ = dvrPoseCreate();
-
- if (!pose_client_) {
- ALOGE("No pose service, returning identity pose");
- return Posef();
- }
- }
-
- DvrPoseState state;
- dvrPosePoll(pose_client_, &state);
-
- const vec4 head_rotation_in_start_quat(
- state.head_from_start_rotation.x, state.head_from_start_rotation.y,
- state.head_from_start_rotation.z, state.head_from_start_rotation.w);
-
- // When the pose service hasn't computed a pose yet, it returns a zero
- // quaternion; just use the identity rotation in that case.
- // TODO(stefanus): Find a better way to signal and check this.
- if (head_rotation_in_start_quat.squaredNorm() < 0.5f) {
- latest_pose_.SetRotation(quat::Identity());
- } else {
- latest_pose_.SetRotation(
- quat(head_rotation_in_start_quat.w(), head_rotation_in_start_quat.x(),
- head_rotation_in_start_quat.y(), head_rotation_in_start_quat.z())
- .normalized());
- }
-
- const vec3 head_position_in_start(state.head_from_start_translation.x,
- state.head_from_start_translation.y,
- state.head_from_start_translation.z);
- latest_pose_.SetPosition(head_position_in_start);
-
- latest_timestamp_ns_ = GetSystemClockNs();
-
- // PoseState pose_state;
- // pose_state.timestamp_ns = latest_timestamp_ns_;
- // pose_state.sensor_from_start_rotation =
- // ion::math::Rotationd::FromQuaternion(ion::math::Vector4d(
- // state.head_from_start_rotation.x, state.head_from_start_rotation.y,
- // state.head_from_start_rotation.z,
- // state.head_from_start_rotation.w));
- //// TODO(stefanus): Determine the first derivative of the rotation and set it
- //// here.
- // pose_state.sensor_from_start_rotation_velocity =
- // ion::math::Vector3d::Zero();
-
- // TODO(stefanus): perform prediction.
-
- return latest_pose_;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libeds/polynomial_radial_distortion.cpp b/libs/vr/libeds/polynomial_radial_distortion.cpp
index fa01bb4..a0c6ea3 100644
--- a/libs/vr/libeds/polynomial_radial_distortion.cpp
+++ b/libs/vr/libeds/polynomial_radial_distortion.cpp
@@ -4,10 +4,13 @@
namespace dvr {
PolynomialRadialDistortion::PolynomialRadialDistortion(
- const std::vector<float>& coefficients)
- : coefficients_(coefficients) {}
+ float polynomial_offset, const std::vector<float>& coefficients)
+ : polynomial_offset_(polynomial_offset), coefficients_(coefficients) {}
float PolynomialRadialDistortion::DistortionFactor(float r_squared) const {
+ if (r_squared < polynomial_offset_)
+ return 1.0f;
+
float r_factor = 1.0f;
float distortion_factor = 1.0f;
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp
index 323236d..9202cd5 100644
--- a/libs/vr/libpdx_uds/client_channel_factory.cpp
+++ b/libs/vr/libpdx_uds/client_channel_factory.cpp
@@ -65,6 +65,7 @@
auto time_end = now + std::chrono::milliseconds{timeout_ms};
bool connected = false;
+ int max_eaccess = 5; // Max number of times to retry when EACCES returned.
while (!connected) {
int64_t timeout = -1;
if (use_timeout) {
@@ -84,10 +85,14 @@
if (ret == -1) {
ALOGD("ClientChannelFactory: Connect error %d: %s", errno,
strerror(errno));
- if (errno == ECONNREFUSED) {
- // Connection refused can be the result of connecting too early (the
- // service socket is created but not being listened to yet).
- ALOGD("ClientChannelFactory: Connection refused, waiting...");
+ // if |max_eaccess| below reaches zero when errno is EACCES, the control
+ // flows into the next "else if" statement and a permanent error is
+ // returned from this function.
+ if (errno == ECONNREFUSED || (errno == EACCES && max_eaccess-- > 0)) {
+ // Connection refused/Permission denied can be the result of connecting
+ // too early (the service socket is created but its access rights are
+ // not set or not being listened to yet).
+ ALOGD("ClientChannelFactory: %s, waiting...", strerror(errno));
using namespace std::literals::chrono_literals;
std::this_thread::sleep_for(100ms);
} else if (errno != ENOENT && errno != ENOTDIR) {
diff --git a/libs/vr/libvrflinger/compositor.cpp b/libs/vr/libvrflinger/compositor.cpp
index 5a111d4..aa01f22 100644
--- a/libs/vr/libvrflinger/compositor.cpp
+++ b/libs/vr/libvrflinger/compositor.cpp
@@ -13,12 +13,12 @@
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/clock_ns.h>
#include <private/dvr/debug.h>
+#include <private/dvr/device_metrics.h>
#include <private/dvr/display_types.h>
#include <private/dvr/dummy_native_window.h>
#include <private/dvr/gl_fenced_flush.h>
#include <private/dvr/graphics/blur.h>
#include <private/dvr/graphics/gpu_profiler.h>
-#include <private/dvr/lucid_metrics.h>
#include <private/dvr/native_buffer.h>
#include <private/dvr/platform_defines.h>
#include <utils/Log.h>
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 8cf9d64..5cdb3bb 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -6,9 +6,9 @@
#include <pdx/default_transport/service_endpoint.h>
#include <pdx/rpc/remote_method.h>
#include <private/dvr/composite_hmd.h>
+#include <private/dvr/device_metrics.h>
#include <private/dvr/display_rpc.h>
#include <private/dvr/display_types.h>
-#include <private/dvr/lucid_metrics.h>
#include <private/dvr/numeric.h>
#include <private/dvr/polynomial_radial_distortion.h>
#include <private/dvr/types.h>
@@ -208,16 +208,16 @@
// We should always have a red distortion.
LOG_FATAL_IF(view_params.distortion_coefficients_r.empty());
- red_distortion = std::make_shared<PolynomialRadialDistortion>(
+ red_distortion = std::make_shared<PolynomialRadialDistortion>(0.0f,
view_params.distortion_coefficients_r);
if (!view_params.distortion_coefficients_g.empty()) {
- green_distortion = std::make_shared<PolynomialRadialDistortion>(
+ green_distortion = std::make_shared<PolynomialRadialDistortion>(0.0f,
view_params.distortion_coefficients_g);
}
if (!view_params.distortion_coefficients_b.empty()) {
- blue_distortion = std::make_shared<PolynomialRadialDistortion>(
+ blue_distortion = std::make_shared<PolynomialRadialDistortion>(0.0f,
view_params.distortion_coefficients_b);
}
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index b096e1c..91923b3 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -185,17 +185,18 @@
struct stat s1, s2;
int fd1, fd2;
fd1 = mMem.handle->data[0];
- fd2 = mem->handle->data[1];
+ fd2 = mem->handle->data[0];
if (fstat(fd1, &s1) < 0 || fstat(fd2, &s2) < 0 || s1.st_ino == s2.st_ino) {
ret = true;
}
break;
}
case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
- LOG_FATAL("%s: Implement GRALLOC or remove", __FUNCTION__);
- ret = true;
+ // there is no known method to test if two gralloc handle are equivalent
+ ret = false;
break;
default:
+ // should never happen
ALOGE("Unexpected mem type %d", mMem.type);
ret = true;
break;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 4d76272..26f9143 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -978,6 +978,7 @@
for (auto &i : mDirectConnections) {
sp<SensorDirectConnection> connection(i.promote());
if (connection != nullptr && connection->isEquivalent(&mem)) {
+ ALOGE("Duplicate create channel request for the same share memory");
return nullptr;
}
}
@@ -988,14 +989,15 @@
int fd = resource->data[0];
int size2 = ashmem_get_size_region(fd);
// check size consistency
- if (size2 != static_cast<int>(size)) {
- ALOGE("Ashmem direct channel size mismatch, %" PRIu32 " vs %d", size, size2);
+ if (size2 < static_cast<int>(size)) {
+ ALOGE("Ashmem direct channel size %" PRIu32 " greater than shared memory size %d",
+ size, size2);
return nullptr;
}
break;
}
case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
- LOG_FATAL("%s: Finish implementation of ION and GRALLOC or remove", __FUNCTION__);
+ // no specific checks for gralloc
break;
default:
ALOGE("Unknown direct connection memory type %d", type);
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 1b598f8..5b869e1 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -32,7 +32,6 @@
#include <hardware/hardware.h>
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
-#include <gui/GraphicBufferAlloc.h>
#include <gui/Surface.h>
#include <ui/GraphicBuffer.h>
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 40979c9..7314127 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -206,7 +206,7 @@
}
disp = DisplayDevice::DISPLAY_EXTERNAL;
}
- mEventHandler->onHotplugReceived(this, disp,
+ mEventHandler->onHotplugReceived(disp,
connected == HWC2::Connection::Connected);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 78d0307..81f1619 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -70,7 +70,7 @@
friend class HWComposer;
virtual void onVSyncReceived(
HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
- virtual void onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) = 0;
+ virtual void onHotplugReceived(int32_t disp, bool connected) = 0;
virtual void onInvalidateReceived(HWComposer* composer) = 0;
protected:
virtual ~EventHandler() {}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
index dcb2913..5b5f1cf 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
@@ -315,7 +315,7 @@
queryDisplayProperties(disp);
// Do not teardown or recreate the primary display
if (disp != HWC_DISPLAY_PRIMARY) {
- mEventHandler.onHotplugReceived(this, disp, bool(connected));
+ mEventHandler.onHotplugReceived(disp, bool(connected));
}
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
index 4bc63bb..f64d69a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
@@ -62,7 +62,7 @@
friend class HWComposer;
virtual void onVSyncReceived(
HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
- virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected) = 0;
+ virtual void onHotplugReceived(int disp, bool connected) = 0;
virtual void onInvalidateReceived(HWComposer* composer) = 0;
protected:
virtual ~EventHandler() {}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 027fae6..5e5efb7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -167,7 +167,7 @@
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer, nullptr, true);
+ BufferQueue::createBufferQueue(&producer, &consumer, true);
mProducer = new MonitoredProducer(producer, mFlinger, this);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 18a7818..a5f1d60 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -45,7 +45,6 @@
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/Surface.h>
-#include <gui/GraphicBufferAlloc.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
@@ -340,12 +339,6 @@
return mBuiltinDisplays[id];
}
-sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
-{
- sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
- return gba;
-}
-
void SurfaceFlinger::bootFinished()
{
if (mStartBootAnimThread->join() != NO_ERROR) {
@@ -606,7 +599,7 @@
// make the GLContext current so that we can create textures when creating
// Layers (which may happens before we render something)
- getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext);
+ getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
@@ -741,11 +734,8 @@
info.density = density;
// TODO: this needs to go away (currently needed only by webkit)
- {
- Mutex::Autolock _l(mStateLock);
- sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
- info.orientation = hw->getOrientation();
- }
+ sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+ info.orientation = hw->getOrientation();
} else {
// TODO: where should this value come from?
static const int TV_DENSITY = 213;
@@ -802,13 +792,10 @@
ALOGE("%s : display is NULL", __func__);
return BAD_VALUE;
}
-
- Mutex::Autolock _l(mStateLock);
sp<DisplayDevice> device(getDisplayDevice(display));
if (device != NULL) {
return device->getActiveConfig();
}
-
return BAD_VALUE;
}
@@ -896,7 +883,6 @@
}
android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
- Mutex::Autolock _l(mStateLock);
sp<DisplayDevice> device(getDisplayDevice(display));
if (device != nullptr) {
return device->getActiveColorMode();
@@ -1158,60 +1144,54 @@
*compositorTiming = mCompositorTiming;
}
-void SurfaceFlinger::createDefaultDisplayDevice() {
- const int32_t type = DisplayDevice::DISPLAY_PRIMARY;
- wp<IBinder> token = mBuiltinDisplays[type];
-
- // All non-virtual displays are currently considered secure.
- const bool isSecure = true;
-
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer, new GraphicBufferAlloc());
-
- sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, type, consumer);
-
- bool hasWideColorModes = false;
- std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(
- type);
- for (android_color_mode_t colorMode : modes) {
- switch (colorMode) {
- case HAL_COLOR_MODE_DISPLAY_P3:
- case HAL_COLOR_MODE_ADOBE_RGB:
- case HAL_COLOR_MODE_DCI_P3:
- hasWideColorModes = true;
- break;
- default:
- break;
- }
- }
- sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure,
- token, fbs, producer, mRenderEngine->getEGLConfig(),
- hasWideColorModes && hasWideColorDisplay);
- mDisplays.add(token, hw);
- android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
- if (hasWideColorModes && hasWideColorDisplay) {
- defaultColorMode = HAL_COLOR_MODE_SRGB;
- }
- setActiveColorModeInternal(hw, defaultColorMode);
-}
-
-void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) {
+void SurfaceFlinger::onHotplugReceived(int32_t disp, bool connected) {
ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false");
-
- if (composer->isUsingVrComposer()) {
- // We handle initializing the primary display device for the VR
- // window manager hwc explicitly at the time of transition.
- if (disp != DisplayDevice::DISPLAY_PRIMARY) {
- ALOGE("External displays are not supported by the vr hardware composer.");
- }
- return;
- }
-
if (disp == DisplayDevice::DISPLAY_PRIMARY) {
Mutex::Autolock lock(mStateLock);
- createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
- createDefaultDisplayDevice();
+
+ // All non-virtual displays are currently considered secure.
+ bool isSecure = true;
+
+ int32_t type = DisplayDevice::DISPLAY_PRIMARY;
+
+ // When we're using the vr composer, the assumption is that we've
+ // already created the IBinder object for the primary display.
+ if (!mHwc->isUsingVrComposer()) {
+ createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
+ }
+
+ wp<IBinder> token = mBuiltinDisplays[type];
+
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc,
+ DisplayDevice::DISPLAY_PRIMARY, consumer);
+
+ bool hasWideColorModes = false;
+ std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type);
+ for (android_color_mode_t colorMode : modes) {
+ switch (colorMode) {
+ case HAL_COLOR_MODE_DISPLAY_P3:
+ case HAL_COLOR_MODE_ADOBE_RGB:
+ case HAL_COLOR_MODE_DCI_P3:
+ hasWideColorModes = true;
+ break;
+ default:
+ break;
+ }
+ }
+ sp<DisplayDevice> hw =
+ new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, disp, isSecure, token, fbs,
+ producer, mRenderEngine->getEGLConfig(),
+ hasWideColorModes && hasWideColorDisplay);
+ mDisplays.add(token, hw);
+ android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
+ if (hasWideColorModes && hasWideColorDisplay) {
+ defaultColorMode = HAL_COLOR_MODE_SRGB;
+ }
+ setActiveColorModeInternal(hw, defaultColorMode);
} else {
auto type = DisplayDevice::DISPLAY_EXTERNAL;
Mutex::Autolock _l(mStateLock);
@@ -1253,7 +1233,6 @@
}
}
-// Note: it is assumed the caller holds |mStateLock| when this is called
void SurfaceFlinger::resetHwc() {
disableHardwareVsync(true);
clearHwcLayers(mDrawingState.layersSortedByZ);
@@ -1263,6 +1242,13 @@
// mCurrentState and mDrawingState and re-apply all changes when we make the
// transition.
mDrawingState.displays.clear();
+ // Release virtual display hwcId during vr mode transition.
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
+ if (displayDevice->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL) {
+ displayDevice->disconnect(getHwComposer());
+ }
+ }
mDisplays.clear();
initializeDisplays();
}
@@ -1274,46 +1260,36 @@
if (vrFlingerRequestsDisplay == mHwc->isUsingVrComposer()) {
return;
}
-
- bool vrHwcNewlyInitialized = false;
-
if (vrFlingerRequestsDisplay && !mVrHwc) {
// Construct new HWComposer without holding any locks.
mVrHwc = new HWComposer(true);
- vrHwcNewlyInitialized = true;
ALOGV("Vr HWC created");
}
+ {
+ Mutex::Autolock _l(mStateLock);
- Mutex::Autolock _l(mStateLock);
+ if (vrFlingerRequestsDisplay) {
+ resetHwc();
- if (vrFlingerRequestsDisplay) {
- resetHwc();
+ mHwc = mVrHwc;
+ mVrFlinger->GrantDisplayOwnership();
+ } else {
+ mVrFlinger->SeizeDisplayOwnership();
- mHwc = mVrHwc;
- mVrFlinger->GrantDisplayOwnership();
+ resetHwc();
- if (vrHwcNewlyInitialized) {
- mVrHwc->setEventHandler(
- static_cast<HWComposer::EventHandler*>(this));
+ mHwc = mRealHwc;
+ enableHardwareVsync();
}
- } else {
- mVrFlinger->SeizeDisplayOwnership();
- resetHwc();
-
- mHwc = mRealHwc;
- enableHardwareVsync();
+ mVisibleRegionsDirty = true;
+ invalidateHwcGeometry();
+ android_atomic_or(1, &mRepaintEverything);
+ setTransactionFlags(eDisplayTransactionNeeded);
}
-
- mVisibleRegionsDirty = true;
- invalidateHwcGeometry();
-
- // Explicitly re-initialize the primary display. This is because some other
- // parts of this class rely on the primary display always being available.
- createDefaultDisplayDevice();
-
- android_atomic_or(1, &mRepaintEverything);
- setTransactionFlags(eDisplayTransactionNeeded);
+ if (mVrHwc) {
+ mVrHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
+ }
}
void SurfaceFlinger::onMessageReceived(int32_t what) {
@@ -1523,8 +1499,7 @@
layer->releasePendingBuffer(dequeueReadyTime);
}
- // |mStateLock| not needed as we are on the main thread
- const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
+ const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
@@ -1872,8 +1847,7 @@
mLastSwapBufferTime = systemTime() - now;
mDebugInSwapBuffers = 0;
- // |mStateLock| not needed as we are on the main thread
- uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+ uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount();
if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
logFrameStats();
}
@@ -1958,7 +1932,7 @@
// Call makeCurrent() on the primary display so we can
// be sure that nothing associated with this display
// is current.
- const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
+ const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice());
defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext);
sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i)));
if (hw != NULL)
@@ -2019,8 +1993,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
- BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
- new GraphicBufferAlloc());
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
int32_t hwcId = -1;
if (state.isVirtualDisplay()) {
@@ -2148,7 +2121,7 @@
// could be null when this layer is using a layerStack
// that is not visible on any display. Also can occur at
// screen off/on times.
- disp = getDefaultDisplayDeviceLocked();
+ disp = getDefaultDisplayDevice();
}
layer->updateTransformHint(disp);
@@ -2504,9 +2477,7 @@
ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
displayDevice->getDisplayName().string());
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
- // |mStateLock| not needed as we are on the main thread
- if(!getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext)) {
+ if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) {
ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
}
return false;
@@ -3598,7 +3569,7 @@
colorizer.reset(result);
HWComposer& hwc(getHwComposer());
- sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
+ sp<const DisplayDevice> hw(getDefaultDisplayDevice());
colorizer.bold(result);
result.appendFormat("EGL implementation : %s\n",
@@ -3828,7 +3799,7 @@
return NO_ERROR;
case 1013: {
Mutex::Autolock _l(mStateLock);
- sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
+ sp<const DisplayDevice> hw(getDefaultDisplayDevice());
reply->writeInt32(hw->getPageFlipCount());
return NO_ERROR;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e9c0acf..b17a5f2 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -76,7 +76,6 @@
class Client;
class DisplayEventConnection;
class EventThread;
-class IGraphicBufferAlloc;
class Layer;
class LayerDim;
class Surface;
@@ -184,9 +183,8 @@
void repaintEverything();
// returns the default Display
- sp<const DisplayDevice> getDefaultDisplayDevice() {
- Mutex::Autolock _l(mStateLock);
- return getDefaultDisplayDeviceLocked();
+ sp<const DisplayDevice> getDefaultDisplayDevice() const {
+ return getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]);
}
// utility function to delete a texture on the main thread
@@ -258,7 +256,6 @@
*/
virtual sp<ISurfaceComposerClient> createConnection();
virtual sp<ISurfaceComposerClient> createScopedConnection(const sp<IGraphicBufferProducer>& gbp);
- virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc();
virtual sp<IBinder> createDisplay(const String8& displayName, bool secure);
virtual void destroyDisplay(const sp<IBinder>& display);
virtual sp<IBinder> getBuiltInDisplay(int32_t id);
@@ -308,7 +305,7 @@
* HWComposer::EventHandler interface
*/
virtual void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp);
- virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected);
+ virtual void onHotplugReceived(int disp, bool connected);
virtual void onInvalidateReceived(HWComposer* composer);
/* ------------------------------------------------------------------------
@@ -443,12 +440,6 @@
return mDisplays.valueFor(dpy);
}
- sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const {
- return getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]);
- }
-
- void createDefaultDisplayDevice();
-
int32_t getDisplayType(const sp<IBinder>& display) {
if (!display.get()) return NAME_NOT_FOUND;
for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 1d2b485..9babeef 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -139,7 +139,9 @@
}
sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
- return mConsumer->getSidebandStream();
+ sp<NativeHandle> stream;
+ mConsumer->getSidebandStream(&stream);
+ return stream;
}
// We need to determine the time when a buffer acquired now will be
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index bdaf85d..59c8b76 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -42,7 +42,6 @@
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/Surface.h>
-#include <gui/GraphicBufferAlloc.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/HdrCapabilities.h>
@@ -319,12 +318,6 @@
return mBuiltinDisplays[id];
}
-sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
-{
- sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
- return gba;
-}
-
void SurfaceFlinger::bootFinished()
{
if (mStartBootAnimThread->join() != NO_ERROR) {
@@ -564,8 +557,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer,
- new GraphicBufferAlloc());
+ BufferQueue::createBufferQueue(&producer, &consumer);
sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
consumer);
@@ -587,7 +579,7 @@
// make the GLContext current so that we can create textures when creating Layers
// (which may happens before we render something)
- getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext);
+ getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
@@ -1058,7 +1050,7 @@
*compositorTiming = mCompositorTiming;
}
-void SurfaceFlinger::onHotplugReceived(HWComposer* /*composer*/, int type, bool connected) {
+void SurfaceFlinger::onHotplugReceived(int type, bool connected) {
if (mEventThread == NULL) {
// This is a temporary workaround for b/7145521. A non-null pointer
// does not mean EventThread has finished initializing, so this
@@ -1705,8 +1697,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
- BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
- new GraphicBufferAlloc());
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
int32_t hwcDisplayId = -1;
if (state.isVirtualDisplay()) {
@@ -3240,7 +3231,7 @@
colorizer.reset(result);
HWComposer& hwc(getHwComposer());
- sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
+ sp<const DisplayDevice> hw(getDefaultDisplayDevice());
colorizer.bold(result);
result.appendFormat("EGL implementation : %s\n",
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
index 45eabca..db7d5dc 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
@@ -28,6 +28,26 @@
ret = parcel->writeBool(frame_.removed);
if (ret != OK) return ret;
+ ret = parcel->writeUint32(static_cast<uint32_t>(frame_.active_config));
+ if (ret != OK) return ret;
+
+ ret = parcel->writeUint32(static_cast<uint32_t>(frame_.color_mode));
+ if (ret != OK) return ret;
+
+ ret = parcel->writeUint32(static_cast<uint32_t>(frame_.power_mode));
+ if (ret != OK) return ret;
+
+ ret = parcel->writeUint32(static_cast<uint32_t>(frame_.vsync_enabled));
+ if (ret != OK) return ret;
+
+ ret = parcel->writeInt32(frame_.color_transform_hint);
+ if (ret != OK) return ret;
+
+ for(size_t i = 0; i < 16; i++) {
+ ret = parcel->writeFloat(frame_.color_transform[i]);
+ if (ret != OK) return ret;
+ }
+
std::vector<ParcelableComposerLayer> layers;
for (size_t i = 0; i < frame_.layers.size(); ++i)
layers.push_back(ParcelableComposerLayer(frame_.layers[i]));
@@ -50,6 +70,31 @@
ret = parcel->readBool(&frame_.removed);
if (ret != OK) return ret;
+ uint32_t value;
+ ret = parcel->readUint32(&value);
+ if (ret != OK) return ret;
+ frame_.active_config = static_cast<Config>(value);
+
+ ret = parcel->readUint32(&value);
+ if (ret != OK) return ret;
+ frame_.color_mode = static_cast<ColorMode>(value);
+
+ ret = parcel->readUint32(&value);
+ if (ret != OK) return ret;
+ frame_.power_mode = static_cast<IComposerClient::PowerMode>(value);
+
+ ret = parcel->readUint32(&value);
+ if (ret != OK) return ret;
+ frame_.vsync_enabled = static_cast<IComposerClient::Vsync>(value);
+
+ ret = parcel->readInt32(&frame_.color_transform_hint);
+ if (ret != OK) return ret;
+
+ for(size_t i = 0; i < 16; i++) {
+ ret = parcel->readFloat(&frame_.color_transform[i]);
+ if (ret != OK) return ret;
+ }
+
std::vector<ParcelableComposerLayer> layers;
ret = parcel->readParcelableVector(&layers);
if (ret != OK) return ret;
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
index 15f63fa..c3621eb 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
@@ -66,6 +66,50 @@
ret = parcel->writeUint32(layer_.app_id);
if (ret != OK) return ret;
+ ret = parcel->writeUint32(layer_.z_order);
+ if (ret != OK) return ret;
+
+ ret = parcel->writeInt32(layer_.cursor_x);
+ if (ret != OK) return ret;
+
+ ret = parcel->writeInt32(layer_.cursor_y);
+ if (ret != OK) return ret;
+
+ uint32_t color = layer_.color.r |
+ (static_cast<uint32_t>(layer_.color.g) << 8) |
+ (static_cast<uint32_t>(layer_.color.b) << 16) |
+ (static_cast<uint32_t>(layer_.color.a) << 24);
+ ret = parcel->writeUint32(color);
+ if (ret != OK) return ret;
+
+ ret = parcel->writeInt32(layer_.dataspace);
+ if (ret != OK) return ret;
+
+ ret = parcel->writeInt32(layer_.transform);
+ if (ret != OK) return ret;
+
+ ret = parcel->writeUint32(static_cast<uint32_t>(layer_.visible_regions.size()));
+ if (ret != OK) return ret;
+
+ for (auto& rect: layer_.visible_regions) {
+ ret = parcel->writeInt32(rect.left);
+ ret = parcel->writeInt32(rect.top);
+ ret = parcel->writeInt32(rect.right);
+ ret = parcel->writeInt32(rect.bottom);
+ if (ret != OK) return ret;
+ }
+
+ ret = parcel->writeUint32(static_cast<uint32_t>(layer_.damaged_regions.size()));
+ if (ret != OK) return ret;
+
+ for (auto& rect: layer_.damaged_regions) {
+ ret = parcel->writeInt32(rect.left);
+ ret = parcel->writeInt32(rect.top);
+ ret = parcel->writeInt32(rect.right);
+ ret = parcel->writeInt32(rect.bottom);
+ if (ret != OK) return ret;
+ }
+
return OK;
}
@@ -125,6 +169,70 @@
ret = parcel->readUint32(&layer_.app_id);
if (ret != OK) return ret;
+ ret = parcel->readUint32(&layer_.z_order);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&layer_.cursor_x);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&layer_.cursor_y);
+ if (ret != OK) return ret;
+
+ uint32_t color;
+ ret = parcel->readUint32(&color);
+ if (ret != OK) return ret;
+ layer_.color.r = color & 0xFF;
+ layer_.color.g = (color >> 8) & 0xFF;
+ layer_.color.b = (color >> 16) & 0xFF;
+ layer_.color.a = (color >> 24) & 0xFF;
+
+ ret = parcel->readInt32(&layer_.dataspace);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&layer_.transform);
+ if (ret != OK) return ret;
+
+ uint32_t size;
+ ret = parcel->readUint32(&size);
+ if (ret != OK) return ret;
+
+ for(size_t i = 0; i < size; i++) {
+ hwc_rect_t rect;
+ ret = parcel->readInt32(&rect.left);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&rect.top);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&rect.right);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&rect.bottom);
+ if (ret != OK) return ret;
+
+ layer_.visible_regions.push_back(rect);
+ }
+
+ ret = parcel->readUint32(&size);
+ if (ret != OK) return ret;
+
+ for(size_t i = 0; i < size; i++) {
+ hwc_rect_t rect;
+ ret = parcel->readInt32(&rect.left);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&rect.top);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&rect.right);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&rect.bottom);
+ if (ret != OK) return ret;
+
+ layer_.damaged_regions.push_back(rect);
+ }
+
return OK;
}
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index 5efc482..f5d88f2 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -132,7 +132,7 @@
std::vector<IComposerClient::Composition>* types) {
std::sort(layers_.begin(), layers_.end(),
[](const auto& lhs, const auto& rhs) {
- return lhs.z_order < rhs.z_order;
+ return lhs.info.z_order < rhs.info.z_order;
});
int first_client_layer = -1, last_client_layer = -1;
@@ -220,6 +220,12 @@
return last_frame_layers;
}
+void HwcDisplay::SetColorTransform(const float* matrix, int32_t hint) {
+ color_transform_hint_ = hint;
+ if (matrix)
+ memcpy(color_transform_, matrix, sizeof(color_transform_));
+}
+
////////////////////////////////////////////////////////////////////////////////
// VrHwcClient
@@ -397,40 +403,54 @@
Error VrHwc::setActiveConfig(Display display, Config config) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
if (config != kDefaultConfigId)
return Error::BAD_CONFIG;
+ display_ptr->set_active_config(config);
return Error::NONE;
}
Error VrHwc::setColorMode(Display display, ColorMode mode) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
+
+ display_ptr->set_color_mode(mode);
return Error::NONE;
}
Error VrHwc::setPowerMode(Display display, IComposerClient::PowerMode mode) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
+
+ display_ptr->set_power_mode(mode);
return Error::NONE;
}
Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
+
+ display_ptr->set_vsync_enabled(enabled);
return Error::NONE;
}
Error VrHwc::setColorTransform(Display display, const float* matrix,
int32_t hint) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
+
+ display_ptr->SetColorTransform(matrix, hint);
return Error::NONE;
}
@@ -500,6 +520,13 @@
frame.display_id = display;
frame.display_width = display_ptr->width();
frame.display_height = display_ptr->height();
+ frame.active_config = display_ptr->active_config();
+ frame.power_mode = display_ptr->power_mode();
+ frame.vsync_enabled = display_ptr->vsync_enabled();
+ frame.color_transform_hint = display_ptr->color_transform_hint();
+ frame.color_mode = display_ptr->color_mode();
+ memcpy(frame.color_transform, display_ptr->color_transform(),
+ sizeof(frame.color_transform));
if (status != Error::NONE)
return status;
@@ -523,8 +550,16 @@
Error VrHwc::setLayerCursorPosition(Display display, Layer layer, int32_t x,
int32_t y) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
+
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
+
+ hwc_layer->info.cursor_x = x;
+ hwc_layer->info.cursor_y = y;
return Error::NONE;
}
@@ -550,8 +585,15 @@
Error VrHwc::setLayerSurfaceDamage(Display display, Layer layer,
const std::vector<hwc_rect_t>& damage) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
+
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
+
+ hwc_layer->info.damaged_regions = damage;
return Error::NONE;
}
@@ -574,8 +616,15 @@
Error VrHwc::setLayerColor(Display display, Layer layer,
IComposerClient::Color color) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
+
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
+
+ hwc_layer->info.color = color;
return Error::NONE;
}
@@ -598,8 +647,15 @@
Error VrHwc::setLayerDataspace(Display display, Layer layer,
int32_t dataspace) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
+
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
+
+ hwc_layer->info.dataspace = dataspace;
return Error::NONE;
}
@@ -662,16 +718,30 @@
Error VrHwc::setLayerTransform(Display display, Layer layer,
int32_t transform) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
+
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
+
+ hwc_layer->info.transform = transform;
return Error::NONE;
}
Error VrHwc::setLayerVisibleRegion(Display display, Layer layer,
const std::vector<hwc_rect_t>& visible) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
return Error::BAD_DISPLAY;
+
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
+
+ hwc_layer->info.visible_regions = visible;
return Error::NONE;
}
@@ -685,7 +755,7 @@
if (!hwc_layer)
return Error::BAD_LAYER;
- hwc_layer->z_order = z;
+ hwc_layer->info.z_order = z;
return Error::NONE;
}
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
index 3da2fb8..609d925 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
@@ -56,8 +56,6 @@
using BlendMode =
hardware::graphics::composer::V2_1::IComposerClient::BlendMode;
- // TODO(dnicoara): Add all layer properties. For now just the basics to get
- // it going.
Layer id;
sp<GraphicBuffer> buffer;
sp<Fence> fence;
@@ -67,6 +65,14 @@
float alpha;
uint32_t type;
uint32_t app_id;
+ uint32_t z_order;
+ int32_t cursor_x;
+ int32_t cursor_y;
+ IComposerClient::Color color;
+ int32_t dataspace;
+ int32_t transform;
+ std::vector<hwc_rect_t> visible_regions;
+ std::vector<hwc_rect_t> damaged_regions;
};
struct Frame {
@@ -77,6 +83,12 @@
bool removed = false;
int32_t display_width;
int32_t display_height;
+ Config active_config;
+ ColorMode color_mode;
+ IComposerClient::PowerMode power_mode;
+ IComposerClient::Vsync vsync_enabled;
+ float color_transform[16];
+ int32_t color_transform_hint;
std::vector<ComposerLayer> layers;
};
@@ -104,7 +116,6 @@
}
Composition composition_type;
- uint32_t z_order;
ComposerView::ComposerLayer info;
IVrComposerClient::BufferMetadata buffer_metadata;
};
@@ -133,6 +144,24 @@
std::vector<Layer> UpdateLastFrameAndGetLastFrameLayers();
+ Config active_config() const { return active_config_; }
+ void set_active_config(Config config) { active_config_ = config; }
+
+ ColorMode color_mode() const { return color_mode_; }
+ void set_color_mode(ColorMode mode) { color_mode_ = mode; }
+
+ IComposerClient::PowerMode power_mode() const { return power_mode_; }
+ void set_power_mode(IComposerClient::PowerMode mode) { power_mode_ = mode; }
+
+ IComposerClient::Vsync vsync_enabled() const { return vsync_enabled_; }
+ void set_vsync_enabled(IComposerClient::Vsync vsync) {
+ vsync_enabled_ = vsync;
+ }
+
+ const float* color_transform() const { return color_transform_; }
+ int32_t color_transform_hint() const { return color_transform_hint_; }
+ void SetColorTransform(const float* matrix, int32_t hint);
+
private:
// The client target buffer and the associated fence.
sp<GraphicBuffer> buffer_;
@@ -150,6 +179,13 @@
int32_t width_;
int32_t height_;
+ Config active_config_;
+ ColorMode color_mode_;
+ IComposerClient::PowerMode power_mode_;
+ IComposerClient::Vsync vsync_enabled_;
+ float color_transform_[16];
+ int32_t color_transform_hint_;
+
HwcDisplay(const HwcDisplay&) = delete;
void operator=(const HwcDisplay&) = delete;
};
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index 43f5042..28e97ff 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -32,6 +32,15 @@
} // namespace
+void HwcCallback::HwcLayer::PrintLayer() {
+ ALOGI("appid=%d, type=%d, alpha=%.2f, cursor=%dx%d, color=%02X%02X%02X%02X, "
+ "crop=%.1f,%.1f,%.1f,%.1f, display=%d,%d,%d,%d, dataspace=%d, "
+ "transform=%d", appid, type, alpha, cursor_x, cursor_y, color.r, color.g,
+ color.b, color.a, crop.left, crop.top, crop.right, crop.bottom,
+ display_frame.left, display_frame.right, display_frame.top,
+ display_frame.bottom, dataspace, transform);
+}
+
HwcCallback::HwcCallback(Client* client) : client_(client) {
}
@@ -54,6 +63,11 @@
.appid = layer.app_id,
.type = static_cast<HwcLayer::LayerType>(layer.type),
.alpha = layer.alpha,
+ .cursor_x = layer.cursor_x,
+ .cursor_y = layer.cursor_y,
+ .color = layer.color,
+ .dataspace = layer.dataspace,
+ .transform = layer.transform,
};
}
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index f1f91a1..4269430 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -65,6 +65,8 @@
}
}
+ void PrintLayer();
+
sp<Fence> fence;
sp<GraphicBuffer> buffer;
Rectf crop;
@@ -73,6 +75,11 @@
uint32_t appid;
LayerType type;
float alpha;
+ int32_t cursor_x;
+ int32_t cursor_y;
+ IComposerClient::Color color;
+ int32_t dataspace;
+ int32_t transform;
};
enum class FrameStatus {