Merge "libpdx_uds: Handle EACCES error when connecting to PDX service" into oc-dev
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 49605be..dab3236 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -547,7 +547,7 @@
TEST_F(UtilsTest, CreatePrimaryCurrentProfile) {
std::string expected =
- create_primary_current_profile_package_dir_path(1, "com.example") + "/primary.prof";
+ create_primary_current_profile_package_dir_path(0, "com.example") + "/primary.prof";
EXPECT_EQ(expected,
create_current_profile_path(/*user*/0, "com.example", /*is_secondary*/false));
}
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 68d39db..39d92a7 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -38,7 +38,7 @@
cc_binary {
name: "vndservicemanager",
defaults: ["servicemanager_flags"],
- proprietary: true,
+ vendor: true,
srcs: [
"service_manager.c",
"binder.c",
@@ -46,6 +46,7 @@
cflags: [
"-DVENDORSERVICEMANAGER=1",
],
- shared_libs: ["libcutils", "libselinux"],
+ shared_libs: ["libcutils"],
+ static_libs: ["libselinux"],
init_rc: ["vndservicemanager.rc"],
}
diff --git a/data/etc/android.hardware.nfc.hce.xml b/data/etc/android.hardware.nfc.hce.xml
index 10b96b1..95da181 100644
--- a/data/etc/android.hardware.nfc.hce.xml
+++ b/data/etc/android.hardware.nfc.hce.xml
@@ -18,4 +18,5 @@
NFC card emulation -->
<permissions>
<feature name="android.hardware.nfc.hce" />
+ <feature name="android.hardware.nfc.any" />
</permissions>
diff --git a/data/etc/android.hardware.nfc.hcef.xml b/data/etc/android.hardware.nfc.hcef.xml
index 0d03023..b86890d 100644
--- a/data/etc/android.hardware.nfc.hcef.xml
+++ b/data/etc/android.hardware.nfc.hcef.xml
@@ -18,4 +18,5 @@
NFC-F card emulation -->
<permissions>
<feature name="android.hardware.nfc.hcef" />
+ <feature name="android.hardware.nfc.any" />
</permissions>
diff --git a/data/etc/android.hardware.nfc.xml b/data/etc/android.hardware.nfc.xml
index 81c4a84..5201fa2 100644
--- a/data/etc/android.hardware.nfc.xml
+++ b/data/etc/android.hardware.nfc.xml
@@ -18,4 +18,5 @@
using Near-Field Communications (NFC). -->
<permissions>
<feature name="android.hardware.nfc" />
+ <feature name="android.hardware.nfc.any" />
</permissions>
diff --git a/data/etc/android.software.autofill.xml b/data/etc/android.software.autofill.xml
new file mode 100644
index 0000000..c510d0c
--- /dev/null
+++ b/data/etc/android.software.autofill.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<permissions>
+ <feature name="android.software.autofill" />
+</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 9229f82..0d5d206 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -49,6 +49,7 @@
<feature name="android.software.activities_on_secondary_displays" />
<feature name="android.software.print" />
<feature name="android.software.companion_device_setup" />
+ <feature name="android.software.autofill" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 64e32ff..9b88648 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -49,6 +49,7 @@
<feature name="android.software.activities_on_secondary_displays" />
<feature name="android.software.print" />
<feature name="android.software.companion_device_setup" />
+ <feature name="android.software.autofill" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 186f62c..cdb3fff 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -484,8 +484,9 @@
*
* Configure sensor direct report on a direct channel: set rate to value other than
* {@link ASENSOR_DIRECT_RATE_STOP} so that sensor event can be directly
- * written into the shared memory region used for creating the buffer; set rate to
- * {@link ASENSOR_DIRECT_RATE_STOP} will stop the sensor direct report.
+ * written into the shared memory region used for creating the buffer. It returns a positive token
+ * which can be used for identify sensor events from different sensors on success. Calling with rate
+ * {@link ASENSOR_DIRECT_RATE_STOP} will stop direct report of the sensor specified in the channel.
*
* To stop all active sensor direct report configured to a channel, set sensor to NULL and rate to
* {@link ASENSOR_DIRECT_RATE_STOP}.
@@ -513,7 +514,7 @@
* {@link ASensorManager_createSharedMemoryDirectChannel} or
* {@link ASensorManager_createHardwareBufferDirectChannel}.
*
- * \return 0 for success or negative integer for failure.
+ * \return positive token for success or negative error code.
*/
int ASensorManager_configureDirectReport(
ASensorManager* manager, ASensor const* sensor, int channelId, int rate);
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index cf2fa47..5d36526 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -72,6 +72,8 @@
status_t appendFrom(const Parcel *parcel,
size_t start, size_t len);
+ int compareData(const Parcel& other);
+
bool allowFds() const;
bool pushAllowFds(bool allowFds);
void restoreAllowFds(bool lastValue);
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..9146340 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -86,7 +86,7 @@
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
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 92251ed..9716be4 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -54,8 +54,7 @@
static constexpr auto EVENT_COUNT =
static_cast<size_t>(FrameEvent::EVENT_COUNT);
static_assert(EVENT_COUNT <= 32, "Event count sanity check failed.");
- static constexpr nsecs_t TIMESTAMP_PENDING =
- std::numeric_limits<nsecs_t>::max();
+ static constexpr nsecs_t TIMESTAMP_PENDING = -2;
static inline bool isValidTimestamp(nsecs_t time) {
return time != TIMESTAMP_PENDING;
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 2fbe07a..9870ba0 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -126,6 +126,11 @@
virtual bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& surface) const = 0;
+ /* Returns the frame timestamps supported by SurfaceFlinger.
+ */
+ virtual status_t getSupportedFrameTimestamps(
+ std::vector<FrameEvent>* outSupported) const = 0;
+
/* set display power mode. depending on the mode, it can either trigger
* screen on, off or low power mode and wait for it to complete.
* requires ACCESS_SURFACE_FLINGER permission.
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 88ef010..8b1d106 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -426,6 +426,10 @@
uint64_t mNextFrameNumber = 1;
uint64_t mLastFrameNumber = 0;
+ // Mutable because ANativeWindow::query needs this class const.
+ mutable bool mQueriedSupportedTimestamps;
+ mutable bool mFrameTimestampsSupportsPresent;
+
// A cached copy of the FrameEventHistory maintained by the consumer.
bool mEnableFrameTimestamps = false;
std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 394425a..ec310cf 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -146,6 +146,8 @@
status_t setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask);
status_t setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent);
status_t setLayer(const sp<IBinder>& id, int32_t layer);
+ status_t setRelativeLayer(const sp<IBinder>& id,
+ const sp<IBinder>& relativeTo, int32_t layer);
status_t setAlpha(const sp<IBinder>& id, float alpha=1.0f);
status_t setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dtdy, float dsdy);
status_t setPosition(const sp<IBinder>& id, float x, float y);
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 3cff7df..712a323 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -62,6 +62,27 @@
status_t setLayerStack(uint32_t layerStack);
status_t setLayer(int32_t layer);
+
+ // Sets a Z order relative to the Surface specified by "relativeTo" but
+ // without becoming a full child of the relative. Z-ordering works exactly
+ // as if it were a child however.
+ //
+ // As a nod to sanity, only non-child surfaces may have a relative Z-order.
+ //
+ // This overrides any previous and is overriden by any future calls
+ // to setLayer.
+ //
+ // If the relative dissapears, the Surface will have no layer and be
+ // invisible, until the next time set(Relative)Layer is called.
+ //
+ // TODO: This is probably a hack. Currently it exists only to work around
+ // some framework usage of the hidden APPLICATION_MEDIA_OVERLAY window type
+ // which allows inserting a window between a SurfaceView and it's main application
+ // window. However, since we are using child windows for the SurfaceView, but not using
+ // child windows elsewhere in O, the WindowManager can't set the layer appropriately.
+ // This is only used by the "TvInputService" and following the port of ViewRootImpl
+ // to child surfaces, we can then port this and remove this method.
+ status_t setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer);
status_t setPosition(float x, float y);
status_t setSize(uint32_t w, uint32_t h);
status_t hide();
diff --git a/include/media/cas/CasAPI.h b/include/media/cas/CasAPI.h
index 0e88019..67f4511 100644
--- a/include/media/cas/CasAPI.h
+++ b/include/media/cas/CasAPI.h
@@ -81,23 +81,12 @@
virtual status_t setPrivateData(
const CasData &privateData) = 0;
- // Open a session for descrambling a program. The session will receive the
- // ECM stream corresponding to the CA_PID for the program.
- virtual status_t openSession(
- uint16_t program_number,
- CasSessionId *sessionId) = 0;
-
- // Open a session for descrambling an elementary stream inside a program.
- // The session will receive the ECM stream corresponding to the CA_PID for
- // the stream.
- virtual status_t openSession(
- uint16_t program_number,
- uint16_t elementary_PID,
- CasSessionId *sessionId) = 0;
+ // Open a session for descrambling a program, or one or more elementary
+ // streams.
+ virtual status_t openSession(CasSessionId *sessionId) = 0;
// Close a previously opened session.
- virtual status_t closeSession(
- const CasSessionId &sessionId) = 0;
+ virtual status_t closeSession(const CasSessionId &sessionId) = 0;
// Provide the CA private data from a CA_descriptor in the program map
// table to a CasPlugin.
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 20f51a5..307c764 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -58,7 +58,8 @@
eOverrideScalingModeChanged = 0x00000800,
eGeometryAppliesWithResize = 0x00001000,
eReparentChildren = 0x00002000,
- eDetachChildren = 0x00004000
+ eDetachChildren = 0x00004000,
+ eRelativeLayerChanged = 0x00008000
};
layer_state_t()
@@ -104,6 +105,8 @@
sp<IGraphicBufferProducer> barrierGbp;
+ sp<IBinder> relativeLayerHandle;
+
// non POD must be last. see write/read
Region transparentRegion;
};
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index da94305..39bb078 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -553,6 +553,14 @@
return err;
}
+int Parcel::compareData(const Parcel& other) {
+ size_t size = dataSize();
+ if (size != other.dataSize()) {
+ return size < other.dataSize() ? -1 : 1;
+ }
+ return memcmp(data(), other.data(), size);
+}
+
bool Parcel::allowFds() const
{
return mAllowFds;
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/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/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..566af90 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -133,7 +133,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 +148,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 +161,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/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index d4e4dc3..1783561 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -270,7 +270,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/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 5a32d05..4d2692f 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -166,6 +166,50 @@
return result != 0;
}
+ virtual status_t getSupportedFrameTimestamps(
+ std::vector<FrameEvent>* outSupported) const {
+ if (!outSupported) {
+ return UNEXPECTED_NULL;
+ }
+ outSupported->clear();
+
+ Parcel data, reply;
+
+ status_t err = data.writeInterfaceToken(
+ ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ err = remote()->transact(
+ BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS,
+ data, &reply);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ int32_t result = 0;
+ err = reply.readInt32(&result);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ std::vector<int32_t> supported;
+ err = reply.readInt32Vector(&supported);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ outSupported->reserve(supported.size());
+ for (int32_t s : supported) {
+ outSupported->push_back(static_cast<FrameEvent>(s));
+ }
+ return NO_ERROR;
+ }
+
virtual sp<IDisplayEventConnection> createDisplayEventConnection()
{
Parcel data, reply;
@@ -536,6 +580,25 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case GET_SUPPORTED_FRAME_TIMESTAMPS: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ std::vector<FrameEvent> supportedTimestamps;
+ status_t result = getSupportedFrameTimestamps(&supportedTimestamps);
+ status_t err = reply->writeInt32(result);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ std::vector<int32_t> supported;
+ supported.reserve(supportedTimestamps.size());
+ for (FrameEvent s : supportedTimestamps) {
+ supported.push_back(static_cast<int32_t>(s));
+ }
+ return reply->writeInt32Vector(supported);
+ }
case CREATE_DISPLAY_EVENT_CONNECTION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IDisplayEventConnection> connection(createDisplayEventConnection());
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 2461cba..9b06e63 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -44,6 +44,7 @@
output.writeUint64(frameNumber);
output.writeInt32(overrideScalingMode);
output.writeStrongBinder(IInterface::asBinder(barrierGbp));
+ output.writeStrongBinder(relativeLayerHandle);
output.write(transparentRegion);
return NO_ERROR;
}
@@ -75,6 +76,7 @@
overrideScalingMode = input.readInt32();
barrierGbp =
interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
+ relativeLayerHandle = input.readStrongBinder();
input.read(transparentRegion);
return NO_ERROR;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1149b89..a6d9e66 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -52,6 +52,8 @@
mAutoRefresh(false),
mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
mSharedBufferHasBeenQueued(false),
+ mQueriedSupportedTimestamps(false),
+ mFrameTimestampsSupportsPresent(false),
mEnableFrameTimestamps(false),
mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>())
{
@@ -209,8 +211,8 @@
bool checkForDisplayPresent = (outDisplayPresentTime != nullptr) &&
!e->hasDisplayPresentInfo();
- // LastRefreshStart, DequeueReady, and Release are never
- // available for the last frame.
+ // LastRefreshStart, DequeueReady, and Release are never available for the
+ // last frame.
bool checkForLastRefreshStart = (outLastRefreshStartTime != nullptr) &&
!e->hasLastRefreshStartInfo() &&
(e->frameNumber != lastFrameNumber);
@@ -227,14 +229,26 @@
static void getFrameTimestamp(nsecs_t *dst, const nsecs_t& src) {
if (dst != nullptr) {
- *dst = FrameEvents::isValidTimestamp(src) ? src : 0;
+ // We always get valid timestamps for these eventually.
+ *dst = (src == FrameEvents::TIMESTAMP_PENDING) ?
+ NATIVE_WINDOW_TIMESTAMP_PENDING : src;
}
}
-static void getFrameTimestampFence(nsecs_t *dst, const std::shared_ptr<FenceTime>& src) {
+static void getFrameTimestampFence(nsecs_t *dst,
+ const std::shared_ptr<FenceTime>& src, bool fenceShouldBeKnown) {
if (dst != nullptr) {
+ if (!fenceShouldBeKnown) {
+ *dst = NATIVE_WINDOW_TIMESTAMP_PENDING;
+ return;
+ }
+
nsecs_t signalTime = src->getSignalTime();
- *dst = Fence::isValidTimestamp(signalTime) ? signalTime : 0;
+ *dst = (signalTime == Fence::SIGNAL_TIME_PENDING) ?
+ NATIVE_WINDOW_TIMESTAMP_PENDING :
+ (signalTime == Fence::SIGNAL_TIME_INVALID) ?
+ NATIVE_WINDOW_TIMESTAMP_INVALID :
+ signalTime;
}
}
@@ -252,6 +266,12 @@
return INVALID_OPERATION;
}
+ // Verify the requested timestamps are supported.
+ querySupportedTimestampsLocked();
+ if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) {
+ return BAD_VALUE;
+ }
+
FrameEvents* events = mFrameEventHistory->getFrame(frameNumber);
if (events == nullptr) {
// If the entry isn't available in the producer, it's definitely not
@@ -282,12 +302,15 @@
getFrameTimestamp(outLastRefreshStartTime, events->lastRefreshStartTime);
getFrameTimestamp(outDequeueReadyTime, events->dequeueReadyTime);
- getFrameTimestampFence(outAcquireTime, events->acquireFence);
- getFrameTimestampFence(
- outGpuCompositionDoneTime, events->gpuCompositionDoneFence);
- getFrameTimestampFence(
- outDisplayPresentTime, events->displayPresentFence);
- getFrameTimestampFence(outReleaseTime, events->releaseFence);
+ getFrameTimestampFence(outAcquireTime, events->acquireFence,
+ events->hasAcquireInfo());
+ getFrameTimestampFence(outGpuCompositionDoneTime,
+ events->gpuCompositionDoneFence,
+ events->hasGpuCompositionDoneInfo());
+ getFrameTimestampFence(outDisplayPresentTime, events->displayPresentFence,
+ events->hasDisplayPresentInfo());
+ getFrameTimestampFence(outReleaseTime, events->releaseFence,
+ events->hasReleaseInfo());
return NO_ERROR;
}
@@ -739,6 +762,29 @@
return err;
}
+void Surface::querySupportedTimestampsLocked() const {
+ // mMutex must be locked when calling this method.
+
+ if (mQueriedSupportedTimestamps) {
+ return;
+ }
+ mQueriedSupportedTimestamps = true;
+
+ std::vector<FrameEvent> supportedFrameTimestamps;
+ status_t err = composerService()->getSupportedFrameTimestamps(
+ &supportedFrameTimestamps);
+
+ if (err != NO_ERROR) {
+ return;
+ }
+
+ for (auto sft : supportedFrameTimestamps) {
+ if (sft == FrameEvent::DISPLAY_PRESENT) {
+ mFrameTimestampsSupportsPresent = true;
+ }
+ }
+}
+
int Surface::query(int what, int* value) const {
ATRACE_CALL();
ALOGV("Surface::query");
@@ -800,6 +846,11 @@
static_cast<int>(durationUs);
return NO_ERROR;
}
+ case NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT: {
+ querySupportedTimestampsLocked();
+ *value = mFrameTimestampsSupportsPresent ? 1 : 0;
+ return NO_ERROR;
+ }
case NATIVE_WINDOW_IS_VALID: {
*value = mGraphicBufferProducer != nullptr ? 1 : 0;
return NO_ERROR;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 56c7586..8c83843 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -149,6 +149,8 @@
uint32_t w, uint32_t h);
status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
int32_t z);
+ status_t setRelativeLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+ const sp<IBinder>& relativeTo, int32_t z);
status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
uint32_t flags, uint32_t mask);
status_t setTransparentRegionHint(
@@ -343,6 +345,20 @@
return NO_ERROR;
}
+status_t Composer::setRelativeLayer(const sp<SurfaceComposerClient>& client,
+ const sp<IBinder>& id, const sp<IBinder>& relativeTo,
+ int32_t z) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s) {
+ return BAD_INDEX;
+ }
+ s->what |= layer_state_t::eRelativeLayerChanged;
+ s->relativeLayerHandle = relativeTo;
+ s->z = z;
+ return NO_ERROR;
+}
+
status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
const sp<IBinder>& id, uint32_t flags,
uint32_t mask) {
@@ -760,6 +776,11 @@
return getComposer().setLayer(this, id, z);
}
+status_t SurfaceComposerClient::setRelativeLayer(const sp<IBinder>& id,
+ const sp<IBinder>& relativeTo, int32_t z) {
+ return getComposer().setRelativeLayer(this, id, relativeTo, z);
+}
+
status_t SurfaceComposerClient::hide(const sp<IBinder>& id) {
return getComposer().setFlags(this, id,
layer_state_t::eLayerHidden,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 7a68f11..bf8a815 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -102,11 +102,19 @@
if (err < 0) return err;
return mClient->setLayerStack(mHandle, layerStack);
}
+
status_t SurfaceControl::setLayer(int32_t layer) {
status_t err = validate();
if (err < 0) return err;
return mClient->setLayer(mHandle, layer);
}
+
+status_t SurfaceControl::setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer) {
+ status_t err = validate();
+ if (err < 0) return err;
+ return mClient->setRelativeLayer(mHandle, relativeTo, layer);
+}
+
status_t SurfaceControl::setPosition(float x, float y) {
status_t err = validate();
if (err < 0) return err;
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 ce11486..cf3d1b2 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -368,6 +368,10 @@
public:
~FakeSurfaceComposer() override {}
+ void setSupportsPresent(bool supportsPresent) {
+ mSupportsPresent = supportsPresent;
+ }
+
sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
sp<ISurfaceComposerClient> createScopedConnection(
const sp<IGraphicBufferProducer>& /* parent */) override {
@@ -391,6 +395,26 @@
const sp<IGraphicBufferProducer>& /*surface*/) const override {
return false;
}
+
+ status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported)
+ const override {
+ *outSupported = {
+ FrameEvent::REQUESTED_PRESENT,
+ FrameEvent::ACQUIRE,
+ FrameEvent::LATCH,
+ FrameEvent::FIRST_REFRESH_START,
+ FrameEvent::LAST_REFRESH_START,
+ FrameEvent::GPU_COMPOSITION_DONE,
+ FrameEvent::DEQUEUE_READY,
+ FrameEvent::RELEASE
+ };
+ if (mSupportsPresent) {
+ outSupported->push_back(
+ FrameEvent::DISPLAY_PRESENT);
+ }
+ return NO_ERROR;
+ }
+
void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
status_t getDisplayConfigs(const sp<IBinder>& /*display*/,
Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
@@ -435,7 +459,6 @@
private:
bool mSupportsPresent{true};
- bool mSupportsRetire{true};
};
class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
@@ -864,6 +887,28 @@
EXPECT_EQ(4, mFakeConsumer->mGetFrameTimestampsCount);
}
+TEST_F(GetFrameTimestampsTest, QueryPresentSupported) {
+ bool displayPresentSupported = true;
+ mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported);
+
+ // Verify supported bits are forwarded.
+ int supportsPresent = -1;
+ mWindow.get()->query(mWindow.get(),
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent);
+ EXPECT_EQ(displayPresentSupported, supportsPresent);
+}
+
+TEST_F(GetFrameTimestampsTest, QueryPresentNotSupported) {
+ bool displayPresentSupported = false;
+ mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported);
+
+ // Verify supported bits are forwarded.
+ int supportsPresent = -1;
+ mWindow.get()->query(mWindow.get(),
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent);
+ EXPECT_EQ(displayPresentSupported, supportsPresent);
+}
+
TEST_F(GetFrameTimestampsTest, SnapToNextTickBasic) {
nsecs_t phase = 4000;
nsecs_t interval = 1000;
@@ -1139,8 +1184,8 @@
EXPECT_EQ(mFrames[1].mRefreshes[0].kGpuCompositionDoneTime,
outGpuCompositionDoneTime);
EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
- EXPECT_EQ(0, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDequeueReadyTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
}
// This test verifies the acquire fence recorded by the consumer is not sent
@@ -1163,7 +1208,7 @@
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
- EXPECT_EQ(0, outAcquireTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outAcquireTime);
// Signal acquire fences. Verify a sync call still isn't necessary.
mFrames[0].signalQueueFences();
@@ -1192,7 +1237,7 @@
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
- EXPECT_EQ(0, outAcquireTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outAcquireTime);
// Signal acquire fences. Verify a sync call still isn't necessary.
mFrames[1].signalQueueFences();
@@ -1228,8 +1273,8 @@
// Verify a request for no timestamps doesn't result in a sync call.
int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
int result = native_window_get_frame_timestamps(mWindow.get(), fId2,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr);
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
}
@@ -1265,10 +1310,10 @@
EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
- EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
// Verify available timestamps are correct for frame 1 again, before any
// fence has been signaled.
@@ -1283,10 +1328,10 @@
EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
- EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
// Signal the fences for frame 1.
mFrames[0].signalRefreshFences();
@@ -1342,10 +1387,10 @@
EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
- EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
// Signal the fences for frame 1.
mFrames[0].signalRefreshFences();
@@ -1363,7 +1408,7 @@
EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
@@ -1371,7 +1416,7 @@
// This test verifies that if the certain timestamps can't possibly exist for
// the most recent frame, then a sync call is not done.
-TEST_F(GetFrameTimestampsTest, NoRetireOrReleaseNoSync) {
+TEST_F(GetFrameTimestampsTest, NoReleaseNoSync) {
enableFrameTimestamps();
// Dequeue and queue frame 1.
@@ -1401,10 +1446,10 @@
EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
- EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
mFrames[0].signalRefreshFences();
mFrames[0].signalReleaseFences();
@@ -1425,10 +1470,33 @@
EXPECT_EQ(mFrames[1].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
- EXPECT_EQ(0, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDequeueReadyTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
+}
+
+// This test verifies there are no sync calls for present times
+// when they aren't supported and that an error is returned.
+
+TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) {
+ enableFrameTimestamps();
+ mSurface->mFakeSurfaceComposer->setSupportsPresent(false);
+
+ // Dequeue and queue frame 1.
+ const uint64_t fId1 = getNextFrameId();
+ dequeueAndQueue(0);
+
+ // Verify a query for the Present times do not trigger a sync call if they
+ // are not supported.
+ resetTimestamps();
+ int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ int result = native_window_get_frame_timestamps(mWindow.get(), fId1,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ &outDisplayPresentTime, nullptr, nullptr);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(BAD_VALUE, result);
+ EXPECT_EQ(-1, outDisplayPresentTime);
}
}
diff --git a/libs/hwc2on1adapter/Android.bp b/libs/hwc2on1adapter/Android.bp
index 438d3f5..5d7f660 100644
--- a/libs/hwc2on1adapter/Android.bp
+++ b/libs/hwc2on1adapter/Android.bp
@@ -14,6 +14,7 @@
cc_library_shared {
name: "libhwc2on1adapter",
+ vendor_available: true,
clang: true,
cppflags: [
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index e35bfc9..8c6ef69 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -2246,6 +2246,11 @@
mHwc1SupportsBackgroundColor = true;
}
}
+
+ // Some devices might have HWC1 retire fences that accurately emulate
+ // HWC2 present fences when they are deferred, but it's not very reliable.
+ // To be safe, we indicate PresentFenceIsNotReliable for all HWC1 devices.
+ mCapabilities.insert(Capability::PresentFenceIsNotReliable);
}
HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id) {
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index a38b4dc..17b2a86 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;
@@ -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/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 63d1ad1..fb67a51 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -186,6 +186,12 @@
* if it is safe (i.e. no crash will occur) to call any method on it.
*/
NATIVE_WINDOW_IS_VALID = 17,
+
+ /*
+ * Returns 1 if NATIVE_WINDOW_GET_FRAME_TIMESTAMPS will return display
+ * present info, 0 if it won't.
+ */
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT = 18,
};
/* Valid operations for the (*perform)() hook.
@@ -305,6 +311,14 @@
*/
static const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
+/* parameter for NATIVE_WINDOW_GET_FRAME_TIMESTAMPS
+ *
+ * Special timestamp value to indicate the timestamps aren't yet known or
+ * that they are invalid.
+ */
+static const int64_t NATIVE_WINDOW_TIMESTAMP_PENDING = -2;
+static const int64_t NATIVE_WINDOW_TIMESTAMP_INVALID = -1;
+
struct ANativeWindow
{
#ifdef __cplusplus
diff --git a/libs/vr/libdvr/display_manager_client.cpp b/libs/vr/libdvr/display_manager_client.cpp
index 9247d53..8d84f7b 100644
--- a/libs/vr/libdvr/display_manager_client.cpp
+++ b/libs/vr/libdvr/display_manager_client.cpp
@@ -111,8 +111,8 @@
}
int dvrDisplayManagerClientGetSurfaceBuffers(
- DvrDisplayManagerClient* client, int surface_id,
- DvrDisplayManagerClientSurfaceBuffers** surface_buffers) {
+ DvrDisplayManagerClient* /* client */, int /* surface_id */,
+ DvrDisplayManagerClientSurfaceBuffers** /* surface_buffers */) {
// TODO(jwcai, hendrikw) Remove this after we replacing
// dvrDisplayManagerClientGetSurfaceBuffers is dvr_api.
return -1;
diff --git a/libs/vr/libdvr/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
index e5665e1..39c2a90 100644
--- a/libs/vr/libdvr/dvr_hardware_composer_client.cpp
+++ b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
@@ -84,7 +84,7 @@
delete frame;
}
-Display dvrHwcFrameGetDisplayId(DvrHwcFrame* frame) {
+DvrHwcDisplay dvrHwcFrameGetDisplayId(DvrHwcFrame* frame) {
return frame->frame.display_id;
}
@@ -104,7 +104,7 @@
return frame->frame.layers.size();
}
-Layer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index) {
+DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index) {
return frame->frame.layers[layer_index].id;
}
@@ -120,8 +120,9 @@
return frame->frame.layers[layer_index].fence->dup();
}
-Recti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame, size_t layer_index) {
- return Recti{
+DvrHwcRecti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame,
+ size_t layer_index) {
+ return DvrHwcRecti{
frame->frame.layers[layer_index].display_frame.left,
frame->frame.layers[layer_index].display_frame.top,
frame->frame.layers[layer_index].display_frame.right,
@@ -129,8 +130,8 @@
};
}
-Rectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index) {
- return Rectf{
+DvrHwcRectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index) {
+ return DvrHwcRectf{
frame->frame.layers[layer_index].crop.left,
frame->frame.layers[layer_index].crop.top,
frame->frame.layers[layer_index].crop.right,
@@ -138,8 +139,10 @@
};
}
-BlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame, size_t layer_index) {
- return static_cast<BlendMode>(frame->frame.layers[layer_index].blend_mode);
+DvrHwcBlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame,
+ size_t layer_index) {
+ return static_cast<DvrHwcBlendMode>(
+ frame->frame.layers[layer_index].blend_mode);
}
float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index) {
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index c46684b..7dc6a30 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -152,23 +152,23 @@
void* client_state);
typedef void (*DvrHwcClientDestroyPtr)(DvrHwcClient* client);
typedef void (*DvrHwcFrameDestroyPtr)(DvrHwcFrame* frame);
-typedef Display (*DvrHwcFrameGetDisplayIdPtr)(DvrHwcFrame* frame);
+typedef DvrHwcDisplay (*DvrHwcFrameGetDisplayIdPtr)(DvrHwcFrame* frame);
typedef int32_t (*DvrHwcFrameGetDisplayWidthPtr)(DvrHwcFrame* frame);
typedef int32_t (*DvrHwcFrameGetDisplayHeightPtr)(DvrHwcFrame* frame);
typedef bool (*DvrHwcFrameGetDisplayRemovedPtr)(DvrHwcFrame* frame);
typedef size_t (*DvrHwcFrameGetLayerCountPtr)(DvrHwcFrame* frame);
-typedef Layer (*DvrHwcFrameGetLayerIdPtr)(DvrHwcFrame* frame,
- size_t layer_index);
+typedef DvrHwcLayer (*DvrHwcFrameGetLayerIdPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
typedef AHardwareBuffer* (*DvrHwcFrameGetLayerBufferPtr)(DvrHwcFrame* frame,
size_t layer_index);
typedef int (*DvrHwcFrameGetLayerFencePtr)(DvrHwcFrame* frame,
size_t layer_index);
-typedef Recti (*DvrHwcFrameGetLayerDisplayFramePtr)(DvrHwcFrame* frame,
- size_t layer_index);
-typedef Rectf (*DvrHwcFrameGetLayerCropPtr)(DvrHwcFrame* frame,
- size_t layer_index);
-typedef BlendMode (*DvrHwcFrameGetLayerBlendModePtr)(DvrHwcFrame* frame,
- size_t layer_index);
+typedef DvrHwcRecti (*DvrHwcFrameGetLayerDisplayFramePtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef DvrHwcRectf (*DvrHwcFrameGetLayerCropPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef DvrHwcBlendMode (*DvrHwcFrameGetLayerBlendModePtr)(DvrHwcFrame* frame,
+ size_t layer_index);
typedef float (*DvrHwcFrameGetLayerAlphaPtr)(DvrHwcFrame* frame,
size_t layer_index);
typedef uint32_t (*DvrHwcFrameGetLayerTypePtr)(DvrHwcFrame* frame,
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 692864d..2d28aa3 100644
--- a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
@@ -29,7 +29,7 @@
// Called to free the frame information.
void dvrHwcFrameDestroy(DvrHwcFrame* frame);
-Display dvrHwcFrameGetDisplayId(DvrHwcFrame* frame);
+DvrHwcDisplay dvrHwcFrameGetDisplayId(DvrHwcFrame* frame);
int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame);
@@ -43,7 +43,7 @@
// @return Number of layers in the frame.
size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame);
-Layer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index);
+DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index);
// Return the graphic buffer associated with the layer at |layer_index| in
// |frame|.
@@ -58,11 +58,13 @@
// @return Fence FD. Caller owns the FD and is responsible for closing it.
int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index);
-Recti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame, size_t layer_index);
+DvrHwcRecti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame,
+ size_t layer_index);
-Rectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index);
+DvrHwcRectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index);
-BlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame, size_t layer_index);
+DvrHwcBlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame,
+ size_t layer_index);
float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index);
diff --git a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
index 546ed7b..36c30f9 100644
--- a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
@@ -10,33 +10,33 @@
// NOTE: These definitions must match the ones in
// //hardware/libhardware/include/hardware/hwcomposer2.h. They are used by the
// client side which does not have access to hwc2 headers.
-enum BlendMode {
- BLEND_MODE_INVALID = 0,
- BLEND_MODE_NONE = 1,
- BLEND_MODE_PREMULTIPLIED = 2,
- BLEND_MODE_COVERAGE = 3,
+enum DvrHwcBlendMode {
+ DVR_HWC_BLEND_MODE_INVALID = 0,
+ DVR_HWC_BLEND_MODE_NONE = 1,
+ DVR_HWC_BLEND_MODE_PREMULTIPLIED = 2,
+ DVR_HWC_BLEND_MODE_COVERAGE = 3,
};
-enum Composition {
- COMPOSITION_INVALID = 0,
- COMPOSITION_CLIENT = 1,
- COMPOSITION_DEVICE = 2,
- COMPOSITION_SOLID_COLOR = 3,
- COMPOSITION_CURSOR = 4,
- COMPOSITION_SIDEBAND = 5,
+enum DvrHwcComposition {
+ DVR_HWC_COMPOSITION_INVALID = 0,
+ DVR_HWC_COMPOSITION_CLIENT = 1,
+ DVR_HWC_COMPOSITION_DEVICE = 2,
+ DVR_HWC_COMPOSITION_SOLID_COLOR = 3,
+ DVR_HWC_COMPOSITION_CURSOR = 4,
+ DVR_HWC_COMPOSITION_SIDEBAND = 5,
};
-typedef uint64_t Display;
-typedef uint64_t Layer;
+typedef uint64_t DvrHwcDisplay;
+typedef uint64_t DvrHwcLayer;
-struct Recti {
+struct DvrHwcRecti {
int32_t left;
int32_t top;
int32_t right;
int32_t bottom;
};
-struct Rectf {
+struct DvrHwcRectf {
float left;
float top;
float right;
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index bf831a7..d0996f0 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -627,19 +627,21 @@
#ifndef EGL_ANDROID_get_frame_timestamps
#define EGL_ANDROID_get_frame_timestamps 1
-#define EGL_TIMESTAMPS_ANDROID 0x314D
-#define EGL_COMPOSITE_DEADLINE_ANDROID 0x314E
-#define EGL_COMPOSITE_INTERVAL_ANDROID 0x314F
-#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3150
-#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3151
-#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3152
-#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3153
-#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3154
-#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
-#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3156
-#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
-#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3158
-#define EGL_READS_DONE_TIME_ANDROID 0x3159
+#define EGL_TIMESTAMPS_ANDROID 0x3430
+#define EGL_COMPOSITE_DEADLINE_ANDROID 0x3431
+#define EGL_COMPOSITE_INTERVAL_ANDROID 0x3432
+#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433
+#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434
+#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435
+#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436
+#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437
+#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438
+#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439
+#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x343A
+#define EGL_DEQUEUE_READY_TIME_ANDROID 0x343B
+#define EGL_READS_DONE_TIME_ANDROID 0x343C
+#define EGL_TIMESTAMP_PENDING_ANDROID EGL_CAST(EGLnsecsANDROID, -2)
+#define EGL_TIMESTAMP_INVALID_ANDROID EGL_CAST(EGLnsecsANDROID, -1)
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
EGLAPI EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index b00d401..0807d1f 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -2166,10 +2166,15 @@
case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID:
- case EGL_DISPLAY_PRESENT_TIME_ANDROID:
case EGL_DEQUEUE_READY_TIME_ANDROID:
case EGL_READS_DONE_TIME_ANDROID:
return EGL_TRUE;
+ case EGL_DISPLAY_PRESENT_TIME_ANDROID: {
+ int value = 0;
+ window->query(window,
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value);
+ return value == 0 ? EGL_FALSE : EGL_TRUE;
+ }
default:
return EGL_FALSE;
}
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index 61b9b66..b8a9add 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -28,7 +28,7 @@
Version
- Version 1, January 13, 2017
+ Version 8, April 11, 2017
Number
@@ -81,19 +81,21 @@
New Tokens
- EGL_TIMESTAMPS_ANDROID 0x314D
- EGL_COMPOSITE_DEADLINE_ANDROID 0x314E
- EGL_COMPOSITE_INTERVAL_ANDROID 0x314F
- EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3150
- EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3151
- EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3152
- EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3153
- EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3154
- EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
- EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3156
- EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
- EGL_DEQUEUE_READY_TIME_ANDROID 0x3158
- EGL_READS_DONE_TIME_ANDROID 0x3159
+ EGL_TIMESTAMPS_ANDROID 0x3430
+ EGL_COMPOSITE_DEADLINE_ANDROID 0x3431
+ EGL_COMPOSITE_INTERVAL_ANDROID 0x3432
+ EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433
+ EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434
+ EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435
+ EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436
+ EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437
+ EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438
+ EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439
+ EGL_DISPLAY_PRESENT_TIME_ANDROID 0x343A
+ EGL_DEQUEUE_READY_TIME_ANDROID 0x343B
+ EGL_READS_DONE_TIME_ANDROID 0x343C
+ EGL_TIMESTAMP_PENDING_ANDROID -2
+ EGL_TIMESTAMP_INVALID_ANDROID -1
Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
"Surface Attributes", page 43:
@@ -155,10 +157,12 @@
limited history of timestamp data. If a query is made for a frame whose
timestamp history no longer exists then EGL_BAD_ACCESS is generated. If
timestamp collection has not been enabled for the surface then
- EGL_BAD_SURFACE is generated. Timestamps for events that will not occur or
- have not yet occurred will be zero. Timestamp queries that are not
- supported will generate an EGL_BAD_PARAMETER error. If any error is
- generated the function will return EGL_FALSE.
+ EGL_BAD_SURFACE is generated. Timestamps for events that might still occur
+ will have the value EGL_TIMESTAMP_PENDING_ANDROID. Timestamps for events
+ that did not occur will have the value EGL_TIMESTAMP_INVALID_ANDROID.
+ Otherwise, the timestamp will be valid and indicate the event has occured.
+ Timestamp queries that are not supported will generate an EGL_BAD_PARAMETER
+ error. If any error is generated the function will return EGL_FALSE.
The application can poll for the timestamp of particular events by calling
eglGetFrameTimestamps over and over without needing to call any other EGL
@@ -222,6 +226,12 @@
Revision History
+#8 (Brian Anderson, April 11, 2017)
+ - Use reserved enumerant values.
+
+#7 (Brian Anderson, March 21, 2017)
+ - Differentiate between pending events and events that did not occur.
+
#6 (Brian Anderson, March 16, 2017)
- Remove DISPLAY_RETIRE_TIME_ANDROID.
diff --git a/opengl/specs/README b/opengl/specs/README
index e922740..cba4453 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -4,8 +4,14 @@
The table below tracks usage of EGL enumerant values that have been reserved
for use by Android extensions.
+See https://github.com/KhronosGroup/EGL-Registry/blob/master/api/egl.xml
+for a list of all enumarant values currently reserved and registered with
+Khronos.
+
Value Extension
----------------- ----------------------------------
+================ ==================================
+0x3140 - 0x314F Reserved block
+================ ==================================
0x3140 EGL_NATIVE_BUFFER_ANDROID (EGL_ANDROID_image_native_buffer)
0x3141 EGL_PLATFORM_ANDROID_KHR (KHR_platform_android)
0x3142 EGL_RECORDABLE_ANDROID (EGL_ANDROID_recordable)
@@ -18,17 +24,23 @@
0x314A EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop)
0x314B EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
0x314C EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh)
-0x314D EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x314E EGL_COMPOSITE_DEADLINE_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x314F EGL_COMPOSITE_INTERVAL_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3150 EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3151 EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3152 EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3153 EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3154 EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3155 EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3156 EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3157 EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3158 EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3159 EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x315A - 0x315F (unused)
+0x314D - 0x314F (unused)
+
+ Value Extension
+================ ==================================
+0x3430 - 0x343F Reserved block
+================ ==================================
+0x3430 EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3431 EGL_COMPOSITE_DEADLINE_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3432 EGL_COMPOSITE_INTERVAL_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3433 EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3434 EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3435 EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3436 EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3437 EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3438 EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3439 EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x343A EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x343B EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x343C EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x343D - 0x343F (unused)
diff --git a/services/schedulerservice/SchedulingPolicyService.cpp b/services/schedulerservice/SchedulingPolicyService.cpp
index a1106cf..1f6ed57 100644
--- a/services/schedulerservice/SchedulingPolicyService.cpp
+++ b/services/schedulerservice/SchedulingPolicyService.cpp
@@ -17,8 +17,6 @@
#include "SchedulingPolicyService.h"
-#include <private/android_filesystem_config.h> // for AID_CAMERASERVER
-
#include <log/log.h>
#include <hwbinder/IPCThreadState.h>
#include <mediautils/SchedulingPolicyService.h>
@@ -30,9 +28,8 @@
namespace implementation {
bool SchedulingPolicyService::isAllowed() {
- using ::android::hardware::IPCThreadState;
-
- return IPCThreadState::self()->getCallingUid() == AID_CAMERASERVER;
+ // TODO(b/37291237)
+ return true;
}
Return<bool> SchedulingPolicyService::requestPriority(int32_t pid, int32_t tid, int32_t priority) {
diff --git a/services/sensorservice/hidl/utils.cpp b/services/sensorservice/hidl/utils.cpp
index b540525..2f9e922 100644
--- a/services/sensorservice/hidl/utils.cpp
+++ b/services/sensorservice/hidl/utils.cpp
@@ -63,6 +63,8 @@
return Result::NO_MEMORY;
case NO_INIT:
return Result::NO_INIT;
+ case PERMISSION_DENIED:
+ return Result::PERMISSION_DENIED;
case BAD_VALUE:
return Result::BAD_VALUE;
case INVALID_OPERATION:
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 76baa01..7bb20ba 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -133,10 +133,15 @@
main_surfaceflinger.cpp
LOCAL_SHARED_LIBRARIES := \
+ android.hardware.configstore@1.0 \
+ android.hardware.configstore-utils \
+ android.hardware.graphics.allocator@2.0 \
libsurfaceflinger \
libcutils \
liblog \
libbinder \
+ libhidlbase \
+ libhidltransport \
libutils \
libui \
libgui \
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 598a65a..027fae6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1713,10 +1713,55 @@
mCurrentState.sequence++;
mCurrentState.z = z;
mCurrentState.modified = true;
+
+ // Discard all relative layering.
+ if (mCurrentState.zOrderRelativeOf != nullptr) {
+ sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
+ if (strongRelative != nullptr) {
+ strongRelative->removeZOrderRelative(this);
+ }
+ mCurrentState.zOrderRelativeOf = nullptr;
+ }
setTransactionFlags(eTransactionNeeded);
return true;
}
+void Layer::removeZOrderRelative(const wp<Layer>& relative) {
+ mCurrentState.zOrderRelatives.remove(relative);
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+}
+
+void Layer::addZOrderRelative(const wp<Layer>& relative) {
+ mCurrentState.zOrderRelatives.add(relative);
+ mCurrentState.modified = true;
+ mCurrentState.sequence++;
+ setTransactionFlags(eTransactionNeeded);
+}
+
+bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t z) {
+ sp<Handle> handle = static_cast<Handle*>(relativeToHandle.get());
+ if (handle == nullptr) {
+ return false;
+ }
+ sp<Layer> relative = handle->owner.promote();
+ if (relative == nullptr) {
+ return false;
+ }
+
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
+ mCurrentState.z = z;
+
+ mCurrentState.zOrderRelativeOf = relative;
+ relative->addZOrderRelative(this);
+
+ setTransactionFlags(eTransactionNeeded);
+
+ return true;
+}
+
bool Layer::setSize(uint32_t w, uint32_t h) {
if (mCurrentState.requested.w == w && mCurrentState.requested.h == h)
return false;
@@ -2500,40 +2545,70 @@
return mDrawingState.z;
}
+LayerVector Layer::makeTraversalList() {
+ if (mDrawingState.zOrderRelatives.size() == 0) {
+ return mDrawingChildren;
+ }
+ LayerVector traverse;
+
+ for (const wp<Layer>& weakRelative : mDrawingState.zOrderRelatives) {
+ sp<Layer> strongRelative = weakRelative.promote();
+ if (strongRelative != nullptr) {
+ traverse.add(strongRelative);
+ } else {
+ // We need to erase from current state instead of drawing
+ // state so we don't overwrite when copying
+ // the current state to the drawing state.
+ mCurrentState.zOrderRelatives.remove(weakRelative);
+ }
+ }
+
+ for (const sp<Layer>& child : mDrawingChildren) {
+ traverse.add(child);
+ }
+
+ return traverse;
+}
+
/**
- * Negatively signed children are before 'this' in Z-order.
+ * Negatively signed relatives are before 'this' in Z-order.
*/
void Layer::traverseInZOrder(const std::function<void(Layer*)>& exec) {
+ LayerVector list = makeTraversalList();
+
size_t i = 0;
- for (; i < mDrawingChildren.size(); i++) {
- const auto& child = mDrawingChildren[i];
- if (child->getZ() >= 0)
+ for (; i < list.size(); i++) {
+ const auto& relative = list[i];
+ if (relative->getZ() >= 0) {
break;
- child->traverseInZOrder(exec);
+ }
+ relative->traverseInZOrder(exec);
}
exec(this);
- for (; i < mDrawingChildren.size(); i++) {
- const auto& child = mDrawingChildren[i];
- child->traverseInZOrder(exec);
+ for (; i < list.size(); i++) {
+ const auto& relative = list[i];
+ relative->traverseInZOrder(exec);
}
}
/**
- * Positively signed children are before 'this' in reverse Z-order.
+ * Positively signed relatives are before 'this' in reverse Z-order.
*/
void Layer::traverseInReverseZOrder(const std::function<void(Layer*)>& exec) {
+ LayerVector list = makeTraversalList();
+
int32_t i = 0;
- for (i = mDrawingChildren.size()-1; i>=0; i--) {
- const auto& child = mDrawingChildren[i];
- if (child->getZ() < 0) {
+ for (i = list.size()-1; i>=0; i--) {
+ const auto& relative = list[i];
+ if (relative->getZ() < 0) {
break;
}
- child->traverseInReverseZOrder(exec);
+ relative->traverseInReverseZOrder(exec);
}
exec(this);
for (; i>=0; i--) {
- const auto& child = mDrawingChildren[i];
- child->traverseInReverseZOrder(exec);
+ const auto& relative = list[i];
+ relative->traverseInReverseZOrder(exec);
}
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e21be8b..a5224ec 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -151,6 +151,12 @@
uint32_t appId;
uint32_t type;
+
+ // If non-null, a Surface this Surface's Z-order is interpreted relative to.
+ wp<Layer> zOrderRelativeOf;
+
+ // A list of surfaces whose Z-order is interpreted relative to ours.
+ SortedVector<wp<Layer>> zOrderRelatives;
};
// -----------------------------------------------------------------------
@@ -173,6 +179,8 @@
bool setFinalCrop(const Rect& crop, bool immediate);
bool setLayer(int32_t z);
+ bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
+
bool setSize(uint32_t w, uint32_t h);
#ifdef USE_HWC2
bool setAlpha(float alpha);
@@ -549,6 +557,10 @@
void setParent(const sp<Layer>& layer);
+ LayerVector makeTraversalList();
+ void addZOrderRelative(const wp<Layer>& relative);
+ void removeZOrderRelative(const wp<Layer>& relative);
+
// -----------------------------------------------------------------------
class SyncPoint
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index 7ba6ad3..90e6395 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -42,13 +42,21 @@
void LayerVector::traverseInZOrder(const std::function<void(Layer*)>& consume) const {
for (size_t i = 0; i < size(); i++) {
- (*this)[i]->traverseInZOrder(consume);
+ const auto& layer = (*this)[i];
+ if (layer->getDrawingState().zOrderRelativeOf != nullptr) {
+ continue;
+ }
+ layer->traverseInZOrder(consume);
}
}
void LayerVector::traverseInReverseZOrder(const std::function<void(Layer*)>& consume) const {
for (auto i = static_cast<int64_t>(size()) - 1; i >= 0; i--) {
- (*this)[i]->traverseInReverseZOrder(consume);
+ const auto& layer = (*this)[i];
+ if (layer->getDrawingState().zOrderRelativeOf != nullptr) {
+ continue;
+ }
+ layer->traverseInReverseZOrder(consume);
}
}
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 76a5d06..c72f8e0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -578,6 +578,14 @@
Mutex::Autolock _l(mStateLock);
+ // Inform native graphics APIs whether the present timestamp is supported:
+ if (getHwComposer().hasCapability(
+ HWC2::Capability::PresentFenceIsNotReliable)) {
+ property_set(kTimestampProperty, "0");
+ } else {
+ property_set(kTimestampProperty, "1");
+ }
+
if (useVrFlinger) {
auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
mVrFlingerRequestsDisplay = requestDisplay;
@@ -598,7 +606,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);
@@ -651,6 +659,25 @@
return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
}
+status_t SurfaceFlinger::getSupportedFrameTimestamps(
+ std::vector<FrameEvent>* outSupported) const {
+ *outSupported = {
+ FrameEvent::REQUESTED_PRESENT,
+ FrameEvent::ACQUIRE,
+ FrameEvent::LATCH,
+ FrameEvent::FIRST_REFRESH_START,
+ FrameEvent::LAST_REFRESH_START,
+ FrameEvent::GPU_COMPOSITION_DONE,
+ FrameEvent::DEQUEUE_READY,
+ FrameEvent::RELEASE,
+ };
+ if (!getHwComposer().hasCapability(
+ HWC2::Capability::PresentFenceIsNotReliable)) {
+ outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
+ }
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
Vector<DisplayInfo>* configs) {
if ((configs == NULL) || (display.get() == NULL)) {
@@ -714,11 +741,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;
@@ -775,13 +799,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;
}
@@ -869,7 +890,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();
@@ -1131,60 +1151,55 @@
*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,
+ new GraphicBufferAlloc());
+
+ 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);
@@ -1226,7 +1241,6 @@
}
}
-// Note: it is assumed the caller holds |mStateLock| when this is called
void SurfaceFlinger::resetHwc() {
disableHardwareVsync(true);
clearHwcLayers(mDrawingState.layersSortedByZ);
@@ -1247,46 +1261,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) {
@@ -1496,8 +1500,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)) {
@@ -1845,8 +1848,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();
}
@@ -1931,7 +1933,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)
@@ -2121,7 +2123,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);
@@ -2477,9 +2479,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;
@@ -2847,6 +2847,11 @@
}
}
}
+ if (what & layer_state_t::eRelativeLayerChanged) {
+ if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eSizeChanged) {
if (layer->setSize(s.w, s.h)) {
flags |= eTraversalNeeded;
@@ -3566,7 +3571,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",
@@ -3796,7 +3801,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 219d662..afb64ed 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -184,9 +184,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
@@ -228,6 +227,7 @@
enum { LOG_FRAME_STATS_PERIOD = 30*60*60 };
static const size_t MAX_LAYERS = 4096;
+ static constexpr const char* kTimestampProperty = "service.sf.present_timestamp";
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -266,6 +266,8 @@
virtual void bootFinished();
virtual bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const;
+ virtual status_t getSupportedFrameTimestamps(
+ std::vector<FrameEvent>* outSupported) const;
virtual sp<IDisplayEventConnection> createDisplayEventConnection();
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
@@ -305,7 +307,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);
/* ------------------------------------------------------------------------
@@ -440,12 +442,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 cd2acef..28dac11 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -549,6 +549,9 @@
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
+ // Inform native graphics APIs that the present timestamp is NOT supported:
+ property_set(kTimestampProperty, "0");
+
// initialize our non-virtual displays
for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
@@ -584,7 +587,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);
@@ -647,6 +650,21 @@
return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
}
+status_t SurfaceFlinger::getSupportedFrameTimestamps(
+ std::vector<FrameEvent>* outSupported) const {
+ *outSupported = {
+ FrameEvent::REQUESTED_PRESENT,
+ FrameEvent::ACQUIRE,
+ FrameEvent::LATCH,
+ FrameEvent::FIRST_REFRESH_START,
+ FrameEvent::LAST_REFRESH_START,
+ FrameEvent::GPU_COMPOSITION_DONE,
+ FrameEvent::DEQUEUE_READY,
+ FrameEvent::RELEASE,
+ };
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
Vector<DisplayInfo>* configs) {
if ((configs == NULL) || (display.get() == NULL)) {
@@ -1040,7 +1058,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
@@ -3222,7 +3240,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/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index f151087..d15376e 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -18,17 +18,44 @@
#include <sched.h>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <cutils/sched_policy.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
+#include <hidl/LegacySupport.h>
+#include <configstore/Utils.h>
#include "GpuService.h"
#include "SurfaceFlinger.h"
using namespace android;
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
+using android::hardware::configstore::getBool;
+using android::hardware::configstore::getBool;
+
+static status_t startGraphicsAllocatorService() {
+ hardware::configureRpcThreadpool( 1 /* maxThreads */,
+ false /* callerWillJoin */);
+ status_t result =
+ hardware::registerPassthroughServiceImplementation<IAllocator>();
+ if (result != OK) {
+ ALOGE("could not start graphics allocator service");
+ return result;
+ }
+
+ return OK;
+}
+
int main(int, char**) {
+ if (getBool<ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::startGraphicsAllocatorService>(false)) {
+ startGraphicsAllocatorService();
+ }
+
signal(SIGPIPE, SIG_IGN);
// When SF is launched in its own process, limit the number of
// binder threads to 4.
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index a46ba48..441fc7e 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -662,6 +662,49 @@
}
}
+TEST_F(LayerUpdateTest, LayerSetRelativeLayerWorks) {
+ sp<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before adding relative surface");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(24, 24);
+ sc->expectFGColor(75, 75);
+ sc->expectBGColor(145, 145);
+ }
+
+ auto relativeSurfaceControl = mComposerClient->createSurface(
+ String8("Test Surface"), 64, 64, PIXEL_FORMAT_RGBA_8888, 0);
+ fillSurfaceRGBA8(relativeSurfaceControl, 255, 177, 177);
+ waitForPostedBuffers();
+
+ // Now we stack the surface above the foreground surface and make sure it is visible.
+ SurfaceComposerClient::openGlobalTransaction();
+ relativeSurfaceControl->setPosition(64, 64);
+ relativeSurfaceControl->show();
+ relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1);
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+
+ {
+ SCOPED_TRACE("after adding relative surface");
+ ScreenCapture::captureScreen(&sc);
+ // our relative surface should be visible now.
+ sc->checkPixel(75, 75, 255, 177, 177);
+ }
+
+ // A call to setLayer will override a call to setRelativeLayer
+ SurfaceComposerClient::openGlobalTransaction();
+ relativeSurfaceControl->setLayer(0);
+ SurfaceComposerClient::closeGlobalTransaction();
+
+ {
+ SCOPED_TRACE("after set layer");
+ ScreenCapture::captureScreen(&sc);
+ // now the FG surface should be visible again.
+ sc->expectFGColor(75, 75);
+ }
+}
+
class ChildLayerTest : public LayerUpdateTest {
protected:
void SetUp() override {
diff --git a/services/vr/vr_window_manager/composer/Android.bp b/services/vr/vr_window_manager/composer/Android.bp
index f01bb28..1998749 100644
--- a/services/vr/vr_window_manager/composer/Android.bp
+++ b/services/vr/vr_window_manager/composer/Android.bp
@@ -10,9 +10,9 @@
static_libs: [
"libhwcomposer-client",
"libdisplay",
- "libpdx_default_transport",
- "libbufferhub",
"libbufferhubqueue",
+ "libbufferhub",
+ "libpdx_default_transport",
],
shared_libs: [
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 3fd8c51..91c270e 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -26,6 +26,7 @@
cc_library_headers {
name: "vulkan_headers",
export_include_dirs: ["include"],
+ vendor_available: true,
}
subdirs = [
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 68f09c4..6149894 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -78,6 +78,7 @@
"libutils",
"libcutils",
"libz",
+ "libnativewindow",
],
static_libs: ["libgrallocusage"],
}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 212d142..f2cd8e6 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -817,9 +817,6 @@
loader_extensions.push_back({
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION});
- loader_extensions.push_back({
- VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
- VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
if (kEnableUnratifiedExtensions) {
// conditionally add shared_presentable_image if supportable
@@ -832,6 +829,16 @@
}
}
+ // conditionally add VK_GOOGLE_display_timing if present timestamps are
+ // supported by the driver:
+ char timestamp_property[PROPERTY_VALUE_MAX];
+ property_get("service.sf.present_timestamp", timestamp_property, "1");
+ if (strcmp(timestamp_property, "1") == 0) {
+ loader_extensions.push_back({
+ VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
+ VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
+ }
+
// enumerate our extensions first
if (!pLayerName && pProperties) {
uint32_t count = std::min(
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 3b785e6..caa2674 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -114,14 +114,34 @@
: vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0},
native_frame_id_(nativeFrameId) {}
bool ready() const {
- return (timestamp_desired_present_time_ &&
- timestamp_actual_present_time_ &&
- timestamp_render_complete_time_ &&
- timestamp_composition_latch_time_);
+ return (timestamp_desired_present_time_ !=
+ NATIVE_WINDOW_TIMESTAMP_PENDING &&
+ timestamp_actual_present_time_ !=
+ NATIVE_WINDOW_TIMESTAMP_PENDING &&
+ timestamp_render_complete_time_ !=
+ NATIVE_WINDOW_TIMESTAMP_PENDING &&
+ timestamp_composition_latch_time_ !=
+ NATIVE_WINDOW_TIMESTAMP_PENDING);
}
- void calculate(uint64_t rdur) {
- vals_.actualPresentTime = timestamp_actual_present_time_;
- uint64_t margin = (timestamp_composition_latch_time_ -
+ void calculate(int64_t rdur) {
+ bool anyTimestampInvalid =
+ (timestamp_actual_present_time_ ==
+ NATIVE_WINDOW_TIMESTAMP_INVALID) ||
+ (timestamp_render_complete_time_ ==
+ NATIVE_WINDOW_TIMESTAMP_INVALID) ||
+ (timestamp_composition_latch_time_ ==
+ NATIVE_WINDOW_TIMESTAMP_INVALID);
+ if (anyTimestampInvalid) {
+ ALOGE("Unexpectedly received invalid timestamp.");
+ vals_.actualPresentTime = 0;
+ vals_.earliestPresentTime = 0;
+ vals_.presentMargin = 0;
+ return;
+ }
+
+ vals_.actualPresentTime =
+ static_cast<uint64_t>(timestamp_actual_present_time_);
+ int64_t margin = (timestamp_composition_latch_time_ -
timestamp_render_complete_time_);
// Calculate vals_.earliestPresentTime, and potentially adjust
// vals_.presentMargin. The initial value of vals_.earliestPresentTime
@@ -132,14 +152,14 @@
// it did (per the extension specification). If for some reason, we
// can do this subtraction repeatedly, we do, since
// vals_.earliestPresentTime really is supposed to be the "earliest".
- uint64_t early_time = vals_.actualPresentTime;
+ int64_t early_time = timestamp_actual_present_time_;
while ((margin > rdur) &&
((early_time - rdur) > timestamp_composition_latch_time_)) {
early_time -= rdur;
margin -= rdur;
}
- vals_.earliestPresentTime = early_time;
- vals_.presentMargin = margin;
+ vals_.earliestPresentTime = static_cast<uint64_t>(early_time);
+ vals_.presentMargin = static_cast<uint64_t>(margin);
}
void get_values(VkPastPresentationTimingGOOGLE* values) const {
*values = vals_;
@@ -149,10 +169,11 @@
VkPastPresentationTimingGOOGLE vals_ { 0, 0, 0, 0, 0 };
uint64_t native_frame_id_ { 0 };
- uint64_t timestamp_desired_present_time_ { 0 };
- uint64_t timestamp_actual_present_time_ { 0 };
- uint64_t timestamp_render_complete_time_ { 0 };
- uint64_t timestamp_composition_latch_time_ { 0 };
+ int64_t timestamp_desired_present_time_{ NATIVE_WINDOW_TIMESTAMP_PENDING };
+ int64_t timestamp_actual_present_time_ { NATIVE_WINDOW_TIMESTAMP_PENDING };
+ int64_t timestamp_render_complete_time_ { NATIVE_WINDOW_TIMESTAMP_PENDING };
+ int64_t timestamp_composition_latch_time_
+ { NATIVE_WINDOW_TIMESTAMP_PENDING };
};
// ----------------------------------------------------------------------------
@@ -187,18 +208,16 @@
shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
ANativeWindow* window = surface.window.get();
- int64_t rdur;
native_window_get_refresh_cycle_duration(
window,
- &rdur);
- refresh_duration = static_cast<uint64_t>(rdur);
+ &refresh_duration);
}
Surface& surface;
uint32_t num_images;
bool mailbox_mode;
bool frame_timestamps_enabled;
- uint64_t refresh_duration;
+ int64_t refresh_duration;
bool shared;
struct Image {
@@ -327,14 +346,10 @@
// Record the timestamp(s) we received, and then see if this TimingInfo
// is ready to be reported to the user:
- ti.timestamp_desired_present_time_ =
- static_cast<uint64_t>(desired_present_time);
- ti.timestamp_actual_present_time_ =
- static_cast<uint64_t>(actual_present_time);
- ti.timestamp_render_complete_time_ =
- static_cast<uint64_t>(render_complete_time);
- ti.timestamp_composition_latch_time_ =
- static_cast<uint64_t>(composition_latch_time);
+ ti.timestamp_desired_present_time_ = desired_present_time;
+ ti.timestamp_actual_present_time_ = actual_present_time;
+ ti.timestamp_render_complete_time_ = render_complete_time;
+ ti.timestamp_composition_latch_time_ = composition_latch_time;
if (ti.ready()) {
// The TimingInfo has received enough timestamps, and should now
@@ -1494,7 +1509,8 @@
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
VkResult result = VK_SUCCESS;
- pDisplayTimingProperties->refreshDuration = swapchain.refresh_duration;
+ pDisplayTimingProperties->refreshDuration =
+ static_cast<uint64_t>(swapchain.refresh_duration);
return result;
}