summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/installd/dexopt.cpp2
-rw-r--r--cmds/vr/pose/Android.mk6
-rw-r--r--cmds/vr/vrscreencap/Android.mk5
-rw-r--r--include/binder/HalToken.h237
-rw-r--r--include/gui/BufferQueueDefs.h6
-rw-r--r--include/gui/IGraphicBufferProducer.h7
-rw-r--r--include/gui/bufferqueue/1.0/B2HProducerListener.h66
-rw-r--r--include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h106
-rw-r--r--include/ui/BufferQueueDefs.h29
-rw-r--r--libs/binder/Android.bp3
-rw-r--r--libs/binder/HalToken.cpp70
-rw-r--r--libs/gui/Android.bp22
-rw-r--r--libs/gui/IGraphicBufferProducer.cpp123
-rw-r--r--libs/gui/bufferqueue/1.0/B2HProducerListener.cpp46
-rw-r--r--libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp1234
-rw-r--r--libs/math/include/math/half.h2
-rw-r--r--libs/vr/libbufferhubqueue/Android.mk2
-rw-r--r--libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp98
-rw-r--r--libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp2
-rw-r--r--libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp3
-rw-r--r--libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp2
-rw-r--r--libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h37
-rw-r--r--libs/vr/libdisplay/display_manager_client.cpp11
-rw-r--r--libs/vr/libdisplay/display_manager_client_impl.cpp22
-rw-r--r--libs/vr/libdisplay/include/private/dvr/display_manager_client.h6
-rw-r--r--libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h3
-rw-r--r--libs/vr/libdisplay/include/private/dvr/display_rpc.h3
-rw-r--r--libs/vr/libvrflinger/display_manager_service.cpp25
-rw-r--r--libs/vr/libvrflinger/display_manager_service.h2
-rw-r--r--libs/vr/libvrflinger/display_surface.cpp16
-rw-r--r--libs/vr/libvrflinger/display_surface.h3
-rw-r--r--opengl/tests/lib/Android.mk1
-rw-r--r--services/sensorservice/SensorDevice.cpp61
-rw-r--r--services/sensorservice/SensorDevice.h33
-rw-r--r--services/sensorservice/SensorRegistrationInfo.h71
-rw-r--r--services/sensorservice/SensorService.cpp40
-rw-r--r--services/sensorservice/SensorService.h2
-rw-r--r--services/surfaceflinger/Android.mk9
-rw-r--r--services/surfaceflinger/DispSync.cpp8
-rw-r--r--services/surfaceflinger/DispSync.h4
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp13
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h4
-rw-r--r--services/surfaceflinger/SurfaceFlingerConsumer.cpp2
-rw-r--r--services/surfaceflinger/SurfaceFlinger_hwc1.cpp12
-rw-r--r--services/surfaceflinger/tests/Android.mk6
-rw-r--r--services/surfaceflinger/tests/Stress_test.cpp50
-rw-r--r--services/surfaceflinger/tests/SurfaceInterceptor_test.cpp16
-rw-r--r--services/vr/bufferhubd/consumer_queue_channel.cpp20
-rw-r--r--vulkan/Android.bp5
-rw-r--r--vulkan/libvulkan/swapchain.cpp4
-rw-r--r--vulkan/nulldrv/null_driver.cpp22
51 files changed, 2044 insertions, 538 deletions
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index a5ac8a4d4e..0d5652fc49 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -529,7 +529,7 @@ static unique_fd open_reference_profile(uid_t uid, const std::string& pkgname, b
static void open_profile_files(uid_t uid, const std::string& pkgname,
/*out*/ std::vector<unique_fd>* profiles_fd, /*out*/ unique_fd* reference_profile_fd) {
// Open the reference profile in read-write mode as profman might need to save the merge.
- reference_profile_fd->reset(open_reference_profile(uid, pkgname, /*read_write*/ true));
+ *reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ true);
if (reference_profile_fd->get() < 0) {
// We can't access the reference profile file.
return;
diff --git a/cmds/vr/pose/Android.mk b/cmds/vr/pose/Android.mk
index 165755102b..de92b5ba56 100644
--- a/cmds/vr/pose/Android.mk
+++ b/cmds/vr/pose/Android.mk
@@ -33,9 +33,3 @@ LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
LOCAL_MODULE := pose
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
-
-ifeq ($(TARGET_BUILD_VARIANT),eng)
-ALL_DEFAULT_INSTALLED_MODULES += pose
-all_modules: pose
-endif
-
diff --git a/cmds/vr/vrscreencap/Android.mk b/cmds/vr/vrscreencap/Android.mk
index 2fa9155aa9..bd0b224e0f 100644
--- a/cmds/vr/vrscreencap/Android.mk
+++ b/cmds/vr/vrscreencap/Android.mk
@@ -21,8 +21,3 @@ LOCAL_MODULE := vrscreencap
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
-
-ifeq ($(TARGET_BUILD_VARIANT),eng)
-ALL_DEFAULT_INSTALLED_MODULES += vrscreencap
-all_modules: vrscreencap
-endif
diff --git a/include/binder/HalToken.h b/include/binder/HalToken.h
deleted file mode 100644
index ce97c786d9..0000000000
--- a/include/binder/HalToken.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_HALTOKEN_H
-#define ANDROID_HALTOKEN_H
-
-#include <binder/Parcel.h>
-#include <hidl/HidlSupport.h>
-
-/**
- * Hybrid Interfaces
- * =================
- *
- * A hybrid interface is a binder interface that
- * 1. is implemented both traditionally and as a wrapper around a hidl
- * interface, and allows querying whether the underlying instance comes from
- * a hidl interface or not; and
- * 2. allows efficient calls to a hidl interface (if the underlying instance
- * comes from a hidl interface) by automatically creating the wrapper in the
- * process that calls it.
- *
- * Terminology:
- * - `HalToken`: The type for a "token" of a hidl interface. This is defined to
- * be compatible with `ITokenManager.hal`.
- * - `HInterface`: The base type for a hidl interface. Currently, it is defined
- * as `::android::hidl::base::V1_0::IBase`.
- * - `HALINTERFACE`: The hidl interface that will be sent through binders.
- * - `INTERFACE`: The binder interface that will be the wrapper of
- * `HALINTERFACE`. `INTERFACE` is supposed to be somewhat similar to
- * `HALINTERFACE`.
- *
- * To demonstrate how this is done, here is an example. Suppose `INTERFACE` is
- * `IFoo` and `HALINTERFACE` is `HFoo`. The required steps are:
- * 1. Use DECLARE_HYBRID_META_INTERFACE instead of DECLARE_META_INTERFACE in the
- * definition of `IFoo`. The usage is
- * DECLARE_HYBRID_META_INTERFACE(IFoo, HFoo)
- * inside the body of `IFoo`.
- * 2. Create a converter class that derives from
- * `H2BConverter<HFoo, IFoo, BnFoo>`. Let us call this `H2BFoo`.
- * 3. Add the following constructor in `H2BFoo` that call the corresponding
- * constructors in `H2BConverter`:
- * H2BFoo(const sp<HalInterface>& base) : CBase(base) {}
- * Note: `CBase = H2BConverter<HFoo, IFoo, BnFoo>` and `HalInterface = HFoo`
- * are member typedefs of `H2BConverter<HFoo, IFoo, BnFoo>`, so the above
- * line can be copied into `H2BFoo`.
- * 4. Implement `IFoo` in `H2BFoo` on top of `HFoo`. `H2BConverter` provides a
- * protected `mBase` of type `sp<HFoo>` that can be used to access the `HFoo`
- * instance. (There is also a public function named `getHalInterface()` that
- * returns `mBase`.)
- * 5. Create a hardware proxy class that derives from
- * `HpInterface<BpFoo, H2BFoo>`. Name this class `HpFoo`. (This name cannot
- * deviate. See step 8 below.)
- * 6. Add the following constructor to `HpFoo`:
- * HpFoo(const sp<IBinder>& base): PBase(base) {}
- * Note: `PBase` a member typedef of `HpInterface<BpFoo, H2BFoo>` that is
- * equal to `HpInterface<BpFoo, H2BFoo>` itself, so the above line can be
- * copied verbatim into `HpFoo`.
- * 7. Delegate all functions in `HpFoo` that come from `IFoo` except
- * `getHalInterface` to the protected member `mBase`,
- * which is defined in `HpInterface<BpFoo, H2BFoo>` (hence in `HpFoo`) with
- * type `IFoo`. (There is also a public function named `getBaseInterface()`
- * that returns `mBase`.)
- * 8. Replace the existing `IMPLEMENT_META_INTERFACE` for INTERFACE by
- * `IMPLEMENT_HYBRID_META_INTERFACE`. Note that this macro relies on the
- * exact naming of `HpFoo`, where `Foo` comes from the interface name `IFoo`.
- * An example usage is
- * IMPLEMENT_HYBRID_META_INTERFACE(IFoo, HFoo, "example.interface.foo");
- *
- * `GETTOKEN` Template Argument
- * ============================
- *
- * Following the instructions above, `H2BConverter` and `HpInterface` would use
- * `transact()` to send over tokens, with `code` (the first argument of
- * `transact()`) equal to a 4-byte value of '_GTK'. If this value clashes with
- * other values already in use in the `Bp` class, it can be changed by supplying
- * the last optional template argument to `H2BConverter` and `HpInterface`.
- *
- */
-
-namespace android {
-
-typedef uint64_t HalToken;
-typedef ::android::hidl::base::V1_0::IBase HInterface;
-
-sp<HInterface> retrieveHalInterface(const HalToken& token);
-bool createHalToken(const sp<HInterface>& interface, HalToken* token);
-bool deleteHalToken(const HalToken& token);
-
-template <
- typename HINTERFACE,
- typename INTERFACE,
- typename BNINTERFACE,
- uint32_t GETTOKEN = '_GTK'>
-class H2BConverter : public BNINTERFACE {
-public:
- typedef H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN> CBase; // Converter Base
- typedef INTERFACE BaseInterface;
- typedef HINTERFACE HalInterface;
- static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
-
- H2BConverter(const sp<HalInterface>& base) : mBase(base) {}
- virtual status_t onTransact(uint32_t code,
- const Parcel& data, Parcel* reply, uint32_t flags = 0);
- sp<HalInterface> getHalInterface() override { return mBase; }
- HalInterface* getBaseInterface() { return mBase.get(); }
-
-protected:
- sp<HalInterface> mBase;
-};
-
-template <
- typename BPINTERFACE,
- typename CONVERTER,
- uint32_t GETTOKEN = '_GTK'>
-class HpInterface : public CONVERTER::BaseInterface {
-public:
- typedef HpInterface<BPINTERFACE, CONVERTER, GETTOKEN> PBase; // Proxy Base
- typedef typename CONVERTER::BaseInterface BaseInterface;
- typedef typename CONVERTER::HalInterface HalInterface;
- static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
-
- explicit HpInterface(const sp<IBinder>& impl);
- sp<HalInterface> getHalInterface() override { return mHal; }
- BaseInterface* getBaseInterface() { return mBase.get(); }
-
-protected:
- sp<IBinder> mImpl;
- sp<BaseInterface> mBase;
- sp<HalInterface> mHal;
- IBinder* onAsBinder() override { return mImpl.get(); }
-};
-
-// ----------------------------------------------------------------------
-
-#define DECLARE_HYBRID_META_INTERFACE(INTERFACE, HAL) \
- static const ::android::String16 descriptor; \
- static ::android::sp<I##INTERFACE> asInterface( \
- const ::android::sp<::android::IBinder>& obj); \
- virtual const ::android::String16& getInterfaceDescriptor() const; \
- I##INTERFACE(); \
- virtual ~I##INTERFACE(); \
- virtual sp<HAL> getHalInterface(); \
-
-
-#define IMPLEMENT_HYBRID_META_INTERFACE(INTERFACE, HAL, NAME) \
- const ::android::String16 I##INTERFACE::descriptor(NAME); \
- const ::android::String16& \
- I##INTERFACE::getInterfaceDescriptor() const { \
- return I##INTERFACE::descriptor; \
- } \
- ::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
- const ::android::sp<::android::IBinder>& obj) \
- { \
- ::android::sp<I##INTERFACE> intr; \
- if (obj != NULL) { \
- intr = static_cast<I##INTERFACE*>( \
- obj->queryLocalInterface( \
- I##INTERFACE::descriptor).get()); \
- if (intr == NULL) { \
- intr = new Hp##INTERFACE(obj); \
- } \
- } \
- return intr; \
- } \
- I##INTERFACE::I##INTERFACE() { } \
- I##INTERFACE::~I##INTERFACE() { } \
- sp<HAL> I##INTERFACE::getHalInterface() { return nullptr; } \
-
-// ----------------------------------------------------------------------
-
-template <
- typename HINTERFACE,
- typename INTERFACE,
- typename BNINTERFACE,
- uint32_t GETTOKEN>
-status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
- onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- if (code == GET_HAL_TOKEN) {
- HalToken token;
- bool result;
- result = createHalToken(mBase, &token);
- if (!result) {
- ALOGE("H2BConverter: Failed to create HAL token.");
- }
- reply->writeBool(result);
- reply->writeUint64(token);
- return NO_ERROR;
- }
- return BNINTERFACE::onTransact(code, data, reply, flags);
-}
-
-template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN>
-HpInterface<BPINTERFACE, CONVERTER, GETTOKEN>::HpInterface(
- const sp<IBinder>& impl) : mImpl(impl) {
- Parcel data, reply;
- data.writeInterfaceToken(BaseInterface::getInterfaceDescriptor());
- if (impl->transact(GET_HAL_TOKEN, data, &reply) == NO_ERROR) {
- bool tokenCreated = reply.readBool();
- HalToken token = reply.readUint64();
- if (!tokenCreated) {
- ALOGE("HpInterface: Sender failed to create HAL token.");
- mBase = new BPINTERFACE(impl);
- } else {
- sp<HInterface> hInterface = retrieveHalInterface(token);
- deleteHalToken(token);
- if (hInterface != nullptr) {
- mHal = static_cast<HalInterface*>(hInterface.get());
- mBase = new CONVERTER(mHal);
- } else {
- ALOGE("HpInterface: Cannot retrieve HAL interface from token.");
- mBase = new BPINTERFACE(impl);
- }
- }
- } else {
- mBase = new BPINTERFACE(impl);
- }
-}
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_HALTOKEN_H
diff --git a/include/gui/BufferQueueDefs.h b/include/gui/BufferQueueDefs.h
index 83e9580037..ffafb49615 100644
--- a/include/gui/BufferQueueDefs.h
+++ b/include/gui/BufferQueueDefs.h
@@ -18,16 +18,12 @@
#define ANDROID_GUI_BUFFERQUEUECOREDEFS_H
#include <gui/BufferSlot.h>
+#include <ui/BufferQueueDefs.h>
namespace android {
class BufferQueueCore;
namespace BufferQueueDefs {
- // BufferQueue will keep track of at most this value of buffers.
- // Attempts at runtime to increase the number of buffers past this
- // will fail.
- enum { NUM_BUFFER_SLOTS = 64 };
-
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
} // namespace BufferQueueDefs
} // namespace android
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 258cd2f9aa..5810335598 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -32,12 +32,17 @@
#include <gui/FrameTimestamps.h>
+#include <hidl/HybridInterface.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+
namespace android {
// ----------------------------------------------------------------------------
class IProducerListener;
class NativeHandle;
class Surface;
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
+ HGraphicBufferProducer;
/*
* This class defines the Binder IPC interface for the producer side of
@@ -56,7 +61,7 @@ class Surface;
class IGraphicBufferProducer : public IInterface
{
public:
- DECLARE_META_INTERFACE(GraphicBufferProducer)
+ DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer)
enum {
// A flag returned by dequeueBuffer when the client needs to call
diff --git a/include/gui/bufferqueue/1.0/B2HProducerListener.h b/include/gui/bufferqueue/1.0/B2HProducerListener.h
new file mode 100644
index 0000000000..fa6c2d9f7f
--- /dev/null
+++ b/include/gui/bufferqueue/1.0/B2HProducerListener.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_B2HPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_B2HPRODUCERLISTENER_H
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <binder/IBinder.h>
+#include <gui/IProducerListener.h>
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener
+ HProducerListener;
+
+typedef ::android::IProducerListener
+ BProducerListener;
+
+struct B2HProducerListener : public HProducerListener {
+ sp<BProducerListener> mBase;
+ B2HProducerListener(sp<BProducerListener> const& base);
+ Return<void> onBufferReleased() override;
+ Return<bool> needsReleaseNotify() override;
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace omx
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_B2HPRODUCERLISTENER_H
+
diff --git a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
new file mode 100644
index 0000000000..93c452a0d6
--- /dev/null
+++ b/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BGRAPHICBUFFERPRODUCER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BGRAPHICBUFFERPRODUCER_H
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <binder/Binder.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+
+#include <hidl/HybridInterface.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::media::V1_0::AnwBuffer;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
+ HGraphicBufferProducer;
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener
+ HProducerListener;
+
+typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
+using ::android::BnGraphicBufferProducer;
+using ::android::IProducerListener;
+
+struct H2BGraphicBufferProducer : public ::android::H2BConverter<
+ HGraphicBufferProducer,
+ BGraphicBufferProducer,
+ BnGraphicBufferProducer> {
+ H2BGraphicBufferProducer(sp<HGraphicBufferProducer> const& base) : CBase(base) {}
+
+ status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
+ status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
+ status_t setAsyncMode(bool async) override;
+ status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
+ uint32_t h, ::android::PixelFormat format, uint32_t usage,
+ FrameEventHistoryDelta* outTimestamps) override;
+ status_t detachBuffer(int slot) override;
+ status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence)
+ override;
+ status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer)
+ override;
+ status_t queueBuffer(int slot,
+ const QueueBufferInput& input,
+ QueueBufferOutput* output) override;
+ status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
+ int query(int what, int* value) override;
+ status_t connect(const sp<IProducerListener>& listener, int api,
+ bool producerControlledByApp, QueueBufferOutput* output) override;
+ status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api)
+ override;
+ status_t setSidebandStream(const sp<NativeHandle>& stream) override;
+ void allocateBuffers(uint32_t width, uint32_t height,
+ ::android::PixelFormat format, uint32_t usage) override;
+ status_t allowAllocation(bool allow) override;
+ status_t setGenerationNumber(uint32_t generationNumber) override;
+ String8 getConsumerName() const override;
+ status_t setSharedBufferMode(bool sharedBufferMode) override;
+ status_t setAutoRefresh(bool autoRefresh) override;
+ status_t setDequeueTimeout(nsecs_t timeout) override;
+ status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence, float outTransformMatrix[16]) override;
+ void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
+ status_t getUniqueId(uint64_t* outId) const override;
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BGRAPHICBUFFERPRODUCER_H
diff --git a/include/ui/BufferQueueDefs.h b/include/ui/BufferQueueDefs.h
new file mode 100644
index 0000000000..56de181bca
--- /dev/null
+++ b/include/ui/BufferQueueDefs.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_UI_BUFFERQUEUEDEFS_H
+#define ANDROID_UI_BUFFERQUEUEDEFS_H
+
+namespace android {
+ namespace BufferQueueDefs {
+ // BufferQueue will keep track of at most this value of buffers.
+ // Attempts at runtime to increase the number of buffers past this
+ // will fail.
+ static constexpr int NUM_BUFFER_SLOTS = 64;
+ } // namespace BufferQueueDefs
+} // namespace android
+
+#endif
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2cb44ebcfc..93b8684ec4 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -34,7 +34,6 @@ cc_library {
"IResultReceiver.cpp",
"IServiceManager.cpp",
"IShellCallback.cpp",
- "HalToken.cpp",
"MemoryBase.cpp",
"MemoryDealer.cpp",
"MemoryHeapBase.cpp",
@@ -66,8 +65,6 @@ cc_library {
"liblog",
"libcutils",
"libutils",
- "libhidlbase",
- "android.hidl.token@1.0",
],
export_shared_lib_headers: [
"libbase",
diff --git a/libs/binder/HalToken.cpp b/libs/binder/HalToken.cpp
deleted file mode 100644
index 6e71a52fa1..0000000000
--- a/libs/binder/HalToken.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-#define LOG_TAG "HalToken"
-
-#include <utils/Log.h>
-#include <binder/HalToken.h>
-
-#include <android/hidl/token/1.0/ITokenManager.h>
-
-namespace android {
-
-using ::android::hidl::token::V1_0::ITokenManager;
-
-sp<ITokenManager> gTokenManager = nullptr;
-
-ITokenManager* getTokenManager() {
- if (gTokenManager != nullptr) {
- return gTokenManager.get();
- }
- gTokenManager = ITokenManager::getService();
- if (gTokenManager == nullptr) {
- ALOGE("Cannot retrieve TokenManager.");
- }
- return gTokenManager.get();
-}
-
-sp<HInterface> retrieveHalInterface(const HalToken& token) {
- auto transaction = getTokenManager()->get(token);
- if (!transaction.isOk()) {
- ALOGE("getHalInterface: Cannot obtain interface from token.");
- return nullptr;
- }
- return static_cast<sp<HInterface> >(transaction);
-}
-
-bool createHalToken(const sp<HInterface>& interface, HalToken* token) {
- auto transaction = getTokenManager()->createToken(interface);
- if (!transaction.isOk()) {
- ALOGE("createHalToken: Cannot create token from interface.");
- return false;
- }
- *token = static_cast<HalToken>(transaction);
- return true;
-}
-
-bool deleteHalToken(const HalToken& token) {
- auto transaction = getTokenManager()->unregister(token);
- if (!transaction.isOk()) {
- ALOGE("deleteHalToken: Cannot unregister hal token.");
- return false;
- }
- return true;
-}
-
-}; // namespace android
-
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 9d2dcb630f..26e6bfe79f 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -41,6 +41,15 @@ cc_library_shared {
// We are aware of the risks inherent in comparing floats for equality
"-Wno-float-equal",
+ // Pure abstract classes trigger this warning
+ "-Wno-weak-vtables",
+
+ // Allow four-character integer literals
+ "-Wno-four-char-constants",
+
+ // Allow documentation warnings
+ "-Wno-documentation",
+
"-DDEBUG_ONLY_CODE=0",
],
@@ -86,6 +95,8 @@ cc_library_shared {
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
"view/Surface.cpp",
+ "bufferqueue/1.0/B2HProducerListener.cpp",
+ "bufferqueue/1.0/H2BGraphicBufferProducer.cpp"
],
shared_libs: [
@@ -98,9 +109,18 @@ cc_library_shared {
"libutils",
"libnativewindow",
"liblog",
+ "libhidlbase",
+ "android.hidl.base@1.0",
+ "android.hidl.token@1.0-utils",
+ "android.hardware.graphics.bufferqueue@1.0",
],
- export_shared_lib_headers: ["libbinder", "libui"],
+ export_shared_lib_headers: [
+ "libbinder",
+ "libui",
+ "android.hidl.token@1.0-utils",
+ "android.hardware.graphics.bufferqueue@1.0",
+ ],
}
subdirs = ["tests"]
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index abdf649bb1..74117c8cd1 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -30,9 +30,14 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+
namespace android {
// ----------------------------------------------------------------------------
+using ::android::hardware::graphics::bufferqueue::V1_0::utils::
+ H2BGraphicBufferProducer;
+
enum {
REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
DEQUEUE_BUFFER,
@@ -485,7 +490,123 @@ public:
// translation unit (see clang warning -Wweak-vtables)
BpGraphicBufferProducer::~BpGraphicBufferProducer() {}
-IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer");
+class HpGraphicBufferProducer : public HpInterface<
+ BpGraphicBufferProducer, H2BGraphicBufferProducer> {
+public:
+ HpGraphicBufferProducer(const sp<IBinder>& base) : PBase(base) {}
+
+ status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override {
+ return mBase->requestBuffer(slot, buf);
+ }
+
+ status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override {
+ return mBase->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+ }
+
+ status_t setAsyncMode(bool async) override {
+ return mBase->setAsyncMode(async);
+ }
+
+ status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage,
+ FrameEventHistoryDelta* outTimestamps) override {
+ return mBase->dequeueBuffer(
+ slot, fence, w, h, format, usage, outTimestamps);
+ }
+
+ status_t detachBuffer(int slot) override {
+ return mBase->detachBuffer(slot);
+ }
+
+ status_t detachNextBuffer(
+ sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) override {
+ return mBase->detachNextBuffer(outBuffer, outFence);
+ }
+
+ status_t attachBuffer(
+ int* outSlot, const sp<GraphicBuffer>& buffer) override {
+ return mBase->attachBuffer(outSlot, buffer);
+ }
+
+ status_t queueBuffer(
+ int slot,
+ const QueueBufferInput& input,
+ QueueBufferOutput* output) override {
+ return mBase->queueBuffer(slot, input, output);
+ }
+
+ status_t cancelBuffer(int slot, const sp<Fence>& fence) override {
+ return mBase->cancelBuffer(slot, fence);
+ }
+
+ int query(int what, int* value) override {
+ return mBase->query(what, value);
+ }
+
+ status_t connect(
+ const sp<IProducerListener>& listener,
+ int api, bool producerControlledByApp,
+ QueueBufferOutput* output) override {
+ return mBase->connect(listener, api, producerControlledByApp, output);
+ }
+
+ status_t disconnect(
+ int api, DisconnectMode mode = DisconnectMode::Api) override {
+ return mBase->disconnect(api, mode);
+ }
+
+ status_t setSidebandStream(const sp<NativeHandle>& stream) override {
+ return mBase->setSidebandStream(stream);
+ }
+
+ void allocateBuffers(uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t usage) override {
+ return mBase->allocateBuffers(width, height, format, usage);
+ }
+
+ status_t allowAllocation(bool allow) override {
+ return mBase->allowAllocation(allow);
+ }
+
+ status_t setGenerationNumber(uint32_t generationNumber) override {
+ return mBase->setGenerationNumber(generationNumber);
+ }
+
+ String8 getConsumerName() const override {
+ return mBase->getConsumerName();
+ }
+
+ status_t setSharedBufferMode(bool sharedBufferMode) override {
+ return mBase->setSharedBufferMode(sharedBufferMode);
+ }
+
+ status_t setAutoRefresh(bool autoRefresh) override {
+ return mBase->setAutoRefresh(autoRefresh);
+ }
+
+ status_t setDequeueTimeout(nsecs_t timeout) override {
+ return mBase->setDequeueTimeout(timeout);
+ }
+
+ status_t getLastQueuedBuffer(
+ sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence,
+ float outTransformMatrix[16]) override {
+ return mBase->getLastQueuedBuffer(
+ outBuffer, outFence, outTransformMatrix);
+ }
+
+ void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override {
+ return mBase->getFrameTimestamps(outDelta);
+ }
+
+ status_t getUniqueId(uint64_t* outId) const override {
+ return mBase->getUniqueId(outId);
+ }
+};
+
+IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer,
+ "android.gui.IGraphicBufferProducer");
// ----------------------------------------------------------------------
diff --git a/libs/gui/bufferqueue/1.0/B2HProducerListener.cpp b/libs/gui/bufferqueue/1.0/B2HProducerListener.cpp
new file mode 100644
index 0000000000..a5f28cdbd7
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/B2HProducerListener.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/bufferqueue/1.0/B2HProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+// B2HProducerListener
+B2HProducerListener::B2HProducerListener(
+ sp<BProducerListener> const& base):
+ mBase(base) {
+}
+
+Return<void> B2HProducerListener::onBufferReleased() {
+ mBase->onBufferReleased();
+ return Void();
+}
+
+Return<bool> B2HProducerListener::needsReleaseNotify() {
+ return mBase->needsReleaseNotify();
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
new file mode 100644
index 0000000000..eafd296681
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -0,0 +1,1234 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "H2BGraphicBufferProducer"
+
+#include <android-base/logging.h>
+
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/1.0/B2HProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using Status = HGraphicBufferProducer::Status;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+typedef ::android::hardware::media::V1_0::Rect HRect;
+typedef ::android::hardware::media::V1_0::Region HRegion;
+
+// Conversion functions
+
+// native_handle_t helper functions.
+
+/**
+ * \brief Take an fd and create a native handle containing only the given fd.
+ * The created handle will need to be deleted manually with
+ * `native_handle_delete()`.
+ *
+ * \param[in] fd The source file descriptor (of type `int`).
+ * \return The create `native_handle_t*` that contains the given \p fd. If the
+ * supplied \p fd is negative, the created native handle will contain no file
+ * descriptors.
+ *
+ * If the native handle cannot be created, the return value will be
+ * `nullptr`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+inline native_handle_t* native_handle_create_from_fd(int fd) {
+ if (fd < 0) {
+ return native_handle_create(0, 0);
+ }
+ native_handle_t* nh = native_handle_create(1, 0);
+ if (nh == nullptr) {
+ return nullptr;
+ }
+ nh->data[0] = fd;
+ return nh;
+}
+
+/**
+ * \brief Extract a file descriptor from a native handle.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \param[in] index The index of the file descriptor in \p nh to read from. This
+ * input has the default value of `0`.
+ * \return The `index`-th file descriptor in \p nh. If \p nh does not have
+ * enough file descriptors, the returned value will be `-1`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+inline int native_handle_read_fd(native_handle_t const* nh, int index = 0) {
+ return ((nh == nullptr) || (nh->numFds == 0) ||
+ (nh->numFds <= index) || (index < 0)) ?
+ -1 : nh->data[index];
+}
+
+/**
+ * \brief Convert `Return<Status>` to `status_t`. This is for legacy binder
+ * calls.
+ *
+ * \param[in] t The source `Return<Status>`.
+ * \return The corresponding `status_t`.
+ *
+ * This function first check if \p t has a transport error. If it does, then the
+ * return value is the transport error code. Otherwise, the return value is
+ * converted from `Status` contained inside \p t.
+ *
+ * Note:
+ * - This `Status` is omx-specific. It is defined in `types.hal`.
+ * - The name of this function is not `convert`.
+ */
+// convert: Return<Status> -> status_t
+inline status_t toStatusT(Return<Status> const& t) {
+ return t.isOk() ? static_cast<status_t>(static_cast<Status>(t)) : UNKNOWN_ERROR;
+}
+
+/**
+ * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `status_t`.
+ */
+// convert: Return<void> -> status_t
+inline status_t toStatusT(Return<void> const& t) {
+ return t.isOk() ? OK : UNKNOWN_ERROR;
+}
+
+/**
+ * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
+ *
+ * \param[out] t The wrapper of type `AnwBuffer`.
+ * \param[in] l The source `GraphicBuffer`.
+ */
+// wrap: GraphicBuffer -> AnwBuffer
+inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
+ t->attr.width = l.getWidth();
+ t->attr.height = l.getHeight();
+ t->attr.stride = l.getStride();
+ t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
+ t->attr.layerCount = l.getLayerCount();
+ t->attr.usage = l.getUsage();
+ t->attr.id = l.getId();
+ t->attr.generationNumber = l.getGenerationNumber();
+ t->nativeHandle = hidl_handle(l.handle);
+}
+
+/**
+ * \brief Convert `AnwBuffer` to `GraphicBuffer`.
+ *
+ * \param[out] l The destination `GraphicBuffer`.
+ * \param[in] t The source `AnwBuffer`.
+ *
+ * This function will duplicate all file descriptors in \p t.
+ */
+// convert: AnwBuffer -> GraphicBuffer
+// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
+inline bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
+ native_handle_t* handle = t.nativeHandle == nullptr ?
+ nullptr : native_handle_clone(t.nativeHandle);
+
+ size_t const numInts = 12 +
+ static_cast<size_t>(handle ? handle->numInts : 0);
+ int32_t* ints = new int32_t[numInts];
+
+ size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
+ int* fds = new int[numFds];
+
+ ints[0] = 'GBFR';
+ ints[1] = static_cast<int32_t>(t.attr.width);
+ ints[2] = static_cast<int32_t>(t.attr.height);
+ ints[3] = static_cast<int32_t>(t.attr.stride);
+ ints[4] = static_cast<int32_t>(t.attr.format);
+ ints[5] = static_cast<int32_t>(t.attr.layerCount);
+ ints[6] = static_cast<int32_t>(t.attr.usage);
+ ints[7] = static_cast<int32_t>(t.attr.id >> 32);
+ ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
+ ints[9] = static_cast<int32_t>(t.attr.generationNumber);
+ ints[10] = 0;
+ ints[11] = 0;
+ if (handle) {
+ ints[10] = static_cast<int32_t>(handle->numFds);
+ ints[11] = static_cast<int32_t>(handle->numInts);
+ int* intsStart = handle->data + handle->numFds;
+ std::copy(handle->data, intsStart, fds);
+ std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
+ }
+
+ void const* constBuffer = static_cast<void const*>(ints);
+ size_t size = numInts * sizeof(int32_t);
+ int const* constFds = static_cast<int const*>(fds);
+ status_t status = l->unflatten(constBuffer, size, constFds, numFds);
+
+ delete [] fds;
+ delete [] ints;
+ native_handle_delete(handle);
+ return status == NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/ui/Fence.cpp
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return The required size of the flat buffer.
+ *
+ * The current version of this function always returns 4, which is the number of
+ * bytes required to store the number of file descriptors contained in the fd
+ * part of the flat buffer.
+ */
+inline size_t getFenceFlattenedSize(hidl_handle const& /* fence */) {
+ return 4;
+};
+
+/**
+ * \brief Return the number of file descriptors contained in a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return `0` if \p fence does not contain a valid file descriptor, or `1`
+ * otherwise.
+ */
+inline size_t getFenceFdCount(hidl_handle const& fence) {
+ return native_handle_read_fd(fence) == -1 ? 0 : 1;
+}
+
+/**
+ * \brief Unflatten `Fence` to `hidl_handle`.
+ *
+ * \param[out] fence The destination `hidl_handle`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will point to a newly created
+ * native handle, which needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+inline status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < 4) {
+ return NO_MEMORY;
+ }
+
+ uint32_t numFdsInHandle;
+ FlattenableUtils::read(buffer, size, numFdsInHandle);
+
+ if (numFdsInHandle > 1) {
+ return BAD_VALUE;
+ }
+
+ if (numFds < numFdsInHandle) {
+ return NO_MEMORY;
+ }
+
+ if (numFdsInHandle) {
+ *nh = native_handle_create_from_fd(*fds);
+ if (*nh == nullptr) {
+ return NO_MEMORY;
+ }
+ *fence = *nh;
+ ++fds;
+ --numFds;
+ } else {
+ *nh = nullptr;
+ *fence = hidl_handle();
+ }
+
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `hidl_handle` as `Fence`.
+ *
+ * \param[in] fence The source `hidl_handle`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+inline status_t flattenFence(hidl_handle const& fence,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFenceFlattenedSize(fence) ||
+ numFds < getFenceFdCount(fence)) {
+ return NO_MEMORY;
+ }
+ // Cast to uint32_t since the size of a size_t can vary between 32- and
+ // 64-bit processes
+ FlattenableUtils::write(buffer, size,
+ static_cast<uint32_t>(getFenceFdCount(fence)));
+ int fd = native_handle_read_fd(fence);
+ if (fd != -1) {
+ *fds = fd;
+ ++fds;
+ --numFds;
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Wrap `Fence` in `hidl_handle`.
+ *
+ * \param[out] t The wrapper of type `hidl_handle`.
+ * \param[out] nh The native handle pointed to by \p t.
+ * \param[in] l The source `Fence`.
+ *
+ * On success, \p nh will hold a newly created native handle, which must be
+ * deleted manually with `native_handle_delete()` afterwards.
+ */
+// wrap: Fence -> hidl_handle
+inline bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l) {
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflattenFence(t, nh, constBuffer, size, constFds, numFds)
+ != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `hidl_handle` to `Fence`.
+ *
+ * \param[out] l The destination `Fence`. `l` must not have been used
+ * (`l->isValid()` must return `false`) before this function is called.
+ * \param[in] t The source `hidl_handle`.
+ *
+ * If \p t contains a valid file descriptor, it will be duplicated.
+ */
+// convert: hidl_handle -> Fence
+inline bool convertTo(Fence* l, hidl_handle const& t) {
+ int fd = native_handle_read_fd(t);
+ if (fd != -1) {
+ fd = dup(fd);
+ if (fd == -1) {
+ return false;
+ }
+ }
+ native_handle_t* nh = native_handle_create_from_fd(fd);
+ if (nh == nullptr) {
+ if (fd != -1) {
+ close(fd);
+ }
+ return false;
+ }
+
+ size_t const baseSize = getFenceFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ native_handle_delete(nh);
+ return false;
+ }
+
+ size_t const baseNumFds = getFenceFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ native_handle_delete(nh);
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (flattenFence(hidl_handle(nh), buffer, size, fds, numFds) != NO_ERROR) {
+ native_handle_delete(nh);
+ return false;
+ }
+ native_handle_delete(nh);
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/ui/Region.cpp
+
+/**
+ * \brief Unflatten `HRegion`.
+ *
+ * \param[out] t The destination `HRegion`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+inline status_t unflatten(HRegion* t, void const*& buffer, size_t& size) {
+ if (size < sizeof(uint32_t)) {
+ return NO_MEMORY;
+ }
+
+ uint32_t numRects = 0;
+ FlattenableUtils::read(buffer, size, numRects);
+ if (size < numRects * sizeof(HRect)) {
+ return NO_MEMORY;
+ }
+ if (numRects > (UINT32_MAX / sizeof(HRect))) {
+ return NO_MEMORY;
+ }
+
+ t->resize(numRects);
+ for (size_t r = 0; r < numRects; ++r) {
+ ::android::Rect rect(::android::Rect::EMPTY_RECT);
+ status_t status = rect.unflatten(buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::advance(buffer, size, sizeof(rect));
+ (*t)[r] = HRect{
+ static_cast<int32_t>(rect.left),
+ static_cast<int32_t>(rect.top),
+ static_cast<int32_t>(rect.right),
+ static_cast<int32_t>(rect.bottom)};
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/IGraphicBufferProducer.cpp:
+// IGraphicBufferProducer::QueueBufferInput
+
+/**
+ * \brief Return a lower bound on the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+ HGraphicBufferProducer::QueueBufferInput const& /* t */) {
+ return sizeof(int64_t) + // timestamp
+ sizeof(int) + // isAutoTimestamp
+ sizeof(android_dataspace) + // dataSpace
+ sizeof(::android::Rect) + // crop
+ sizeof(int) + // scalingMode
+ sizeof(uint32_t) + // transform
+ sizeof(uint32_t) + // stickyTransform
+ sizeof(bool); // getFrameTimestamps
+}
+
+/**
+ * \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The destination `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+inline status_t unflatten(
+ HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < minFlattenedSize(*t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, t->timestamp);
+ int lIsAutoTimestamp;
+ FlattenableUtils::read(buffer, size, lIsAutoTimestamp);
+ t->isAutoTimestamp = static_cast<int32_t>(lIsAutoTimestamp);
+ android_dataspace_t lDataSpace;
+ FlattenableUtils::read(buffer, size, lDataSpace);
+ t->dataSpace = static_cast<Dataspace>(lDataSpace);
+ ::android::Rect lCrop;
+ FlattenableUtils::read(buffer, size, lCrop);
+ t->crop = HRect{
+ static_cast<int32_t>(lCrop.left),
+ static_cast<int32_t>(lCrop.top),
+ static_cast<int32_t>(lCrop.right),
+ static_cast<int32_t>(lCrop.bottom)};
+ int lScalingMode;
+ FlattenableUtils::read(buffer, size, lScalingMode);
+ t->scalingMode = static_cast<int32_t>(lScalingMode);
+ FlattenableUtils::read(buffer, size, t->transform);
+ FlattenableUtils::read(buffer, size, t->stickyTransform);
+ FlattenableUtils::read(buffer, size, t->getFrameTimestamps);
+
+ status_t status = unflattenFence(&(t->fence), nh,
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return unflatten(&(t->surfaceDamage), buffer, size);
+}
+
+/**
+ * \brief Wrap `IGraphicBufferProducer::QueueBufferInput` in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in] l The source `IGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If the return value is `true` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+inline bool wrapAs(
+ HGraphicBufferProducer::QueueBufferInput* t,
+ native_handle_t** nh,
+ BGraphicBufferProducer::QueueBufferInput const& l) {
+
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(
+ HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+ constexpr size_t min = sizeof(t.state);
+ switch (t.state) {
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+ return min;
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+ return min + getFenceFlattenedSize(t.fence);
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+ return min + sizeof(
+ ::android::FenceTime::Snapshot::signalTime);
+ }
+ return 0;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The number of file descriptors contained in \p snapshot.
+ */
+inline size_t getFdCount(
+ HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+ return t.state ==
+ HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE ?
+ getFenceFdCount(t.fence) : 0;
+}
+
+/**
+ * \brief Flatten `FenceTimeSnapshot`.
+ *
+ * \param[in] t The source `FenceTimeSnapshot`.
+ * \param[out] nh The cloned native handle, if necessary.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence` if `t.state ==
+ * FENCE`, in which case \p nh will be returned.
+ */
+inline status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
+ native_handle_t** nh,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ *nh = nullptr;
+ switch (t.state) {
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::EMPTY);
+ return NO_ERROR;
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::FENCE);
+ *nh = t.fence.getNativeHandle() == nullptr ?
+ nullptr : native_handle_clone(t.fence);
+ return flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::SIGNAL_TIME);
+ FlattenableUtils::write(buffer, size, t.signalTimeNs);
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta
+
+/**
+ * \brief Return a lower bound on the size of the non-fd buffer required to
+ * flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+ HGraphicBufferProducer::FrameEventsDelta const& /* t */) {
+ return sizeof(uint64_t) + // mFrameNumber
+ sizeof(uint8_t) + // mIndex
+ sizeof(uint8_t) + // mAddPostCompositeCalled
+ sizeof(uint8_t) + // mAddRetireCalled
+ sizeof(uint8_t) + // mAddReleaseCalled
+ sizeof(nsecs_t) + // mPostedTime
+ sizeof(nsecs_t) + // mRequestedPresentTime
+ sizeof(nsecs_t) + // mLatchTime
+ sizeof(nsecs_t) + // mFirstRefreshStartTime
+ sizeof(nsecs_t); // mLastRefreshStartTime
+}
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventsDelta const& t) {
+ return minFlattenedSize(t) +
+ getFlattenedSize(t.gpuCompositionDoneFence) +
+ getFlattenedSize(t.displayPresentFence) +
+ getFlattenedSize(t.displayRetireFence) +
+ getFlattenedSize(t.releaseFence);
+};
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+inline size_t getFdCount(
+ HGraphicBufferProducer::FrameEventsDelta const& t) {
+ return getFdCount(t.gpuCompositionDoneFence) +
+ getFdCount(t.displayPresentFence) +
+ getFdCount(t.displayRetireFence) +
+ getFdCount(t.releaseFence);
+};
+
+/**
+ * \brief Flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The source `FrameEventsDelta`.
+ * \param[out] nh The array of native handles that are cloned.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * On success, this function will duplicate file descriptors contained in \p t.
+ * The cloned native handles will be stored in \p nh. These native handles will
+ * need to be closed by the caller.
+ */
+// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
+// FrameEventsDelta::flatten
+inline status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
+ std::vector<native_handle_t*>* nh,
+ void*& buffer, size_t& size, int*& fds, size_t numFds) {
+ // Check that t.index is within a valid range.
+ if (t.index >= static_cast<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
+ || t.index > std::numeric_limits<uint8_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ FlattenableUtils::write(buffer, size, t.frameNumber);
+
+ // These are static_cast to uint8_t for alignment.
+ FlattenableUtils::write(buffer, size, static_cast<uint8_t>(t.index));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addPostCompositeCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addRetireCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addReleaseCalled));
+
+ FlattenableUtils::write(buffer, size, t.postedTimeNs);
+ FlattenableUtils::write(buffer, size, t.requestedPresentTimeNs);
+ FlattenableUtils::write(buffer, size, t.latchTimeNs);
+ FlattenableUtils::write(buffer, size, t.firstRefreshStartTimeNs);
+ FlattenableUtils::write(buffer, size, t.lastRefreshStartTimeNs);
+ FlattenableUtils::write(buffer, size, t.dequeueReadyTime);
+
+ // Fences
+ HGraphicBufferProducer::FenceTimeSnapshot const* tSnapshot[4];
+ tSnapshot[0] = &t.gpuCompositionDoneFence;
+ tSnapshot[1] = &t.displayPresentFence;
+ tSnapshot[2] = &t.displayRetireFence;
+ tSnapshot[3] = &t.releaseFence;
+ nh->resize(4);
+ for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+ status_t status = flatten(
+ *(tSnapshot[snapshotIndex]),
+ &((*nh)[snapshotIndex]),
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ while (snapshotIndex > 0) {
+ --snapshotIndex;
+ native_handle_close((*nh)[snapshotIndex]);
+ native_handle_delete((*nh)[snapshotIndex]);
+ (*nh)[snapshotIndex] = nullptr;
+ }
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+ size_t size = 4 + // mDeltas.size()
+ sizeof(t.compositorTiming);
+ for (size_t i = 0; i < t.deltas.size(); ++i) {
+ size += getFlattenedSize(t.deltas[i]);
+ }
+ return size;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+inline size_t getFdCount(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+ size_t numFds = 0;
+ for (size_t i = 0; i < t.deltas.size(); ++i) {
+ numFds += getFdCount(t.deltas[i]);
+ }
+ return numFds;
+}
+
+/**
+ * \brief Flatten `FrameEventHistoryDelta`.
+ *
+ * \param[in] t The source `FrameEventHistoryDelta`.
+ * \param[out] nh The array of arrays of cloned native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * On success, this function will duplicate file descriptors contained in \p t.
+ * The cloned native handles will be stored in \p nh. Before making the call, \p
+ * nh should have enough space to store `n` pointers to arrays of native
+ * handles, where `n` is the length of `t.deltas`, and each `nh[i]` should have
+ * enough space to store `4` native handles.
+ */
+inline status_t flatten(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, t.compositorTiming);
+
+ FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
+ nh->resize(t.deltas.size());
+ for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
+ status_t status = flatten(
+ t.deltas[deltaIndex], &((*nh)[deltaIndex]),
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ while (deltaIndex > 0) {
+ --deltaIndex;
+ for (size_t snapshotIndex = 0;
+ snapshotIndex < 4; ++snapshotIndex) {
+ native_handle_close((*nh)[deltaIndex][snapshotIndex]);
+ native_handle_delete((*nh)[deltaIndex][snapshotIndex]);
+ (*nh)[deltaIndex][snapshotIndex] = nullptr;
+ }
+ }
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to
+ * `::android::FrameEventHistoryDelta`.
+ *
+ * \param[out] l The destination `::android::FrameEventHistoryDelta`.
+ * \param[in] t The source `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+inline bool convertTo(
+ ::android::FrameEventHistoryDelta* l,
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = getFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ std::vector<std::vector<native_handle_t*> > nhAA;
+ if (flatten(t, &nhAA, buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ for (auto nhA : nhAA) {
+ for (auto nh : nhA) {
+ if (nh != nullptr) {
+ native_handle_close(nh);
+ native_handle_delete(nh);
+ }
+ }
+ }
+ return false;
+ }
+
+ for (auto nhA : nhAA) {
+ for (auto nh : nhA) {
+ if (nh != nullptr) {
+ native_handle_delete(nh);
+ }
+ }
+ }
+ return true;
+}
+
+// Ref: frameworks/native/libs/gui/IGraphicBufferProducer.cpp:
+// IGraphicBufferProducer::QueueBufferOutput
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
+ * `IGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] l The destination `IGraphicBufferProducer::QueueBufferOutput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+// convert: HGraphicBufferProducer::QueueBufferOutput ->
+// IGraphicBufferProducer::QueueBufferOutput
+inline bool convertTo(
+ BGraphicBufferProducer::QueueBufferOutput* l,
+ HGraphicBufferProducer::QueueBufferOutput const& t) {
+ if (!convertTo(&(l->frameTimestamps), t.frameTimestamps)) {
+ return false;
+ }
+ l->width = t.width;
+ l->height = t.height;
+ l->transformHint = t.transformHint;
+ l->numPendingBuffers = t.numPendingBuffers;
+ l->nextFrameNumber = t.nextFrameNumber;
+ l->bufferReplaced = t.bufferReplaced;
+ return true;
+}
+
+/**
+ * \brief Convert `IGraphicBufferProducer::DisconnectMode` to
+ * `HGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `IGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
+ */
+inline HGraphicBufferProducer::DisconnectMode toHDisconnectMode(
+ BGraphicBufferProducer::DisconnectMode l) {
+ switch (l) {
+ case BGraphicBufferProducer::DisconnectMode::Api:
+ return HGraphicBufferProducer::DisconnectMode::API;
+ case BGraphicBufferProducer::DisconnectMode::AllLocal:
+ return HGraphicBufferProducer::DisconnectMode::ALL_LOCAL;
+ }
+ return HGraphicBufferProducer::DisconnectMode::API;
+}
+
+// H2BGraphicBufferProducer
+
+status_t H2BGraphicBufferProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+ *buf = new GraphicBuffer();
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->requestBuffer(
+ static_cast<int32_t>(slot),
+ [&fnStatus, &buf] (Status status, AnwBuffer const& buffer) {
+ fnStatus = toStatusT(status);
+ if (!convertTo(buf->get(), buffer)) {
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::setMaxDequeuedBufferCount(
+ int maxDequeuedBuffers) {
+ return toStatusT(mBase->setMaxDequeuedBufferCount(
+ static_cast<int32_t>(maxDequeuedBuffers)));
+}
+
+status_t H2BGraphicBufferProducer::setAsyncMode(bool async) {
+ return toStatusT(mBase->setAsyncMode(async));
+}
+
+status_t H2BGraphicBufferProducer::dequeueBuffer(
+ int* slot, sp<Fence>* fence,
+ uint32_t w, uint32_t h, ::android::PixelFormat format,
+ uint32_t usage, FrameEventHistoryDelta* outTimestamps) {
+ *fence = new Fence();
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->dequeueBuffer(
+ w, h, static_cast<PixelFormat>(format), usage,
+ outTimestamps != nullptr,
+ [&fnStatus, slot, fence, outTimestamps] (
+ Status status,
+ int32_t tSlot,
+ hidl_handle const& tFence,
+ HGraphicBufferProducer::FrameEventHistoryDelta const& tTs) {
+ fnStatus = toStatusT(status);
+ *slot = tSlot;
+ if (!convertTo(fence->get(), tFence)) {
+ ALOGE("H2BGraphicBufferProducer::dequeueBuffer - "
+ "Invalid output fence");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ if (outTimestamps && !convertTo(outTimestamps, tTs)) {
+ ALOGE("H2BGraphicBufferProducer::dequeueBuffer - "
+ "Invalid output timestamps");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::detachBuffer(int slot) {
+ return toStatusT(mBase->detachBuffer(static_cast<int>(slot)));
+}
+
+status_t H2BGraphicBufferProducer::detachNextBuffer(
+ sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
+ *outBuffer = new GraphicBuffer();
+ *outFence = new Fence();
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->detachNextBuffer(
+ [&fnStatus, outBuffer, outFence] (
+ Status status,
+ AnwBuffer const& tBuffer,
+ hidl_handle const& tFence) {
+ fnStatus = toStatusT(status);
+ if (!convertTo(outFence->get(), tFence)) {
+ ALOGE("H2BGraphicBufferProducer::detachNextBuffer - "
+ "Invalid output fence");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ if (!convertTo(outBuffer->get(), tBuffer)) {
+ ALOGE("H2BGraphicBufferProducer::detachNextBuffer - "
+ "Invalid output buffer");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::attachBuffer(
+ int* outSlot, const sp<GraphicBuffer>& buffer) {
+ AnwBuffer tBuffer;
+ wrapAs(&tBuffer, *buffer);
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->attachBuffer(tBuffer,
+ [&fnStatus, outSlot] (Status status, int32_t slot) {
+ fnStatus = toStatusT(status);
+ *outSlot = slot;
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::queueBuffer(
+ int slot,
+ const QueueBufferInput& input,
+ QueueBufferOutput* output) {
+ HGraphicBufferProducer::QueueBufferInput tInput;
+ native_handle_t* nh;
+ if (!wrapAs(&tInput, &nh, input)) {
+ ALOGE("H2BGraphicBufferProducer::queueBuffer - "
+ "Invalid input");
+ return BAD_VALUE;
+ }
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->queueBuffer(slot, tInput,
+ [&fnStatus, output] (
+ Status status,
+ HGraphicBufferProducer::QueueBufferOutput const& tOutput) {
+ fnStatus = toStatusT(status);
+ if (!convertTo(output, tOutput)) {
+ ALOGE("H2BGraphicBufferProducer::queueBuffer - "
+ "Invalid output");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ }));
+ native_handle_delete(nh);
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
+ hidl_handle tFence;
+ native_handle_t* nh = nullptr;
+ if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+ ALOGE("H2BGraphicBufferProducer::cancelBuffer - "
+ "Invalid input fence");
+ return BAD_VALUE;
+ }
+
+ status_t status = toStatusT(mBase->cancelBuffer(
+ static_cast<int32_t>(slot), tFence));
+ native_handle_delete(nh);
+ return status;
+}
+
+int H2BGraphicBufferProducer::query(int what, int* value) {
+ int result;
+ status_t transStatus = toStatusT(mBase->query(
+ static_cast<int32_t>(what),
+ [&result, value] (int32_t tResult, int32_t tValue) {
+ result = static_cast<int>(tResult);
+ *value = static_cast<int>(tValue);
+ }));
+ return transStatus == NO_ERROR ? result : static_cast<int>(transStatus);
+}
+
+status_t H2BGraphicBufferProducer::connect(
+ const sp<IProducerListener>& listener, int api,
+ bool producerControlledByApp, QueueBufferOutput* output) {
+ sp<HProducerListener> tListener = listener == nullptr ?
+ nullptr : new B2HProducerListener(listener);
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->connect(
+ tListener, static_cast<int32_t>(api), producerControlledByApp,
+ [&fnStatus, output] (
+ Status status,
+ HGraphicBufferProducer::QueueBufferOutput const& tOutput) {
+ fnStatus = toStatusT(status);
+ if (!convertTo(output, tOutput)) {
+ ALOGE("H2BGraphicBufferProducer::connect - "
+ "Invalid output");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::disconnect(int api, DisconnectMode mode) {
+ return toStatusT(mBase->disconnect(
+ static_cast<int32_t>(api), toHDisconnectMode(mode)));
+}
+
+status_t H2BGraphicBufferProducer::setSidebandStream(
+ const sp<NativeHandle>& stream) {
+ return toStatusT(mBase->setSidebandStream(stream->handle()));
+}
+
+void H2BGraphicBufferProducer::allocateBuffers(uint32_t width, uint32_t height,
+ ::android::PixelFormat format, uint32_t usage) {
+ mBase->allocateBuffers(
+ width, height, static_cast<PixelFormat>(format), usage);
+}
+
+status_t H2BGraphicBufferProducer::allowAllocation(bool allow) {
+ return toStatusT(mBase->allowAllocation(allow));
+}
+
+status_t H2BGraphicBufferProducer::setGenerationNumber(uint32_t generationNumber) {
+ return toStatusT(mBase->setGenerationNumber(generationNumber));
+}
+
+String8 H2BGraphicBufferProducer::getConsumerName() const {
+ String8 lName;
+ mBase->getConsumerName([&lName] (hidl_string const& name) {
+ lName = name.c_str();
+ });
+ return lName;
+}
+
+status_t H2BGraphicBufferProducer::setSharedBufferMode(bool sharedBufferMode) {
+ return toStatusT(mBase->setSharedBufferMode(sharedBufferMode));
+}
+
+status_t H2BGraphicBufferProducer::setAutoRefresh(bool autoRefresh) {
+ return toStatusT(mBase->setAutoRefresh(autoRefresh));
+}
+
+status_t H2BGraphicBufferProducer::setDequeueTimeout(nsecs_t timeout) {
+ return toStatusT(mBase->setDequeueTimeout(static_cast<int64_t>(timeout)));
+}
+
+status_t H2BGraphicBufferProducer::getLastQueuedBuffer(
+ sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence,
+ float outTransformMatrix[16]) {
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->getLastQueuedBuffer(
+ [&fnStatus, outBuffer, outFence, &outTransformMatrix] (
+ Status status,
+ AnwBuffer const& buffer,
+ hidl_handle const& fence,
+ hidl_array<float, 16> const& transformMatrix) {
+ fnStatus = toStatusT(status);
+ *outBuffer = new GraphicBuffer();
+ if (!convertTo(outBuffer->get(), buffer)) {
+ ALOGE("H2BGraphicBufferProducer::getLastQueuedBuffer - "
+ "Invalid output buffer");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ *outFence = new Fence();
+ if (!convertTo(outFence->get(), fence)) {
+ ALOGE("H2BGraphicBufferProducer::getLastQueuedBuffer - "
+ "Invalid output fence");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ std::copy(transformMatrix.data(),
+ transformMatrix.data() + 16,
+ outTransformMatrix);
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+void H2BGraphicBufferProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
+ mBase->getFrameTimestamps([outDelta] (
+ HGraphicBufferProducer::FrameEventHistoryDelta const& tDelta) {
+ convertTo(outDelta, tDelta);
+ });
+}
+
+status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const {
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->getUniqueId(
+ [&fnStatus, outId] (Status status, uint64_t id) {
+ fnStatus = toStatusT(status);
+ *outId = id;
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/libs/math/include/math/half.h b/libs/math/include/math/half.h
index 3ca8bd1873..ef1e45fd9c 100644
--- a/libs/math/include/math/half.h
+++ b/libs/math/include/math/half.h
@@ -21,6 +21,7 @@
#include <limits>
#include <type_traits>
+#ifndef LIKELY
#ifdef __cplusplus
# define LIKELY( exp ) (__builtin_expect( !!(exp), true ))
# define UNLIKELY( exp ) (__builtin_expect( !!(exp), false ))
@@ -28,6 +29,7 @@
# define LIKELY( exp ) (__builtin_expect( !!(exp), 1 ))
# define UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 ))
#endif
+#endif
#if __cplusplus >= 201402L
#define CONSTEXPR constexpr
diff --git a/libs/vr/libbufferhubqueue/Android.mk b/libs/vr/libbufferhubqueue/Android.mk
index 3ed7ff2b4a..d53f06af70 100644
--- a/libs/vr/libbufferhubqueue/Android.mk
+++ b/libs/vr/libbufferhubqueue/Android.mk
@@ -36,10 +36,12 @@ sharedLibraries := \
liblog \
libui \
libutils \
+ libgui \
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(sourceFiles)
LOCAL_C_INCLUDES := $(includeFiles)
+LOCAL_CFLAGS := -DLOG_TAG=\"libbufferhubqueue\"
LOCAL_EXPORT_C_INCLUDE_DIRS := $(includeFiles)
LOCAL_STATIC_LIBRARIES := $(staticLibraries)
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 0576b21a21..bad9503383 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -1,5 +1,7 @@
#include "include/private/dvr/buffer_hub_queue_client.h"
+//#define LOG_NDEBUG 0
+
#include <inttypes.h>
#include <log/log.h>
#include <sys/epoll.h>
@@ -24,6 +26,7 @@ BufferHubQueue::BufferHubQueue(LocalChannelHandle channel_handle,
meta_size_(meta_size),
meta_buffer_tmp_(meta_size ? new uint8_t[meta_size] : nullptr),
buffers_(BufferHubQueue::kMaxQueueCapacity),
+ epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
available_buffers_(BufferHubQueue::kMaxQueueCapacity),
capacity_(0) {
Initialize();
@@ -36,6 +39,7 @@ BufferHubQueue::BufferHubQueue(const std::string& endpoint_path,
meta_size_(meta_size),
meta_buffer_tmp_(meta_size ? new uint8_t[meta_size] : nullptr),
buffers_(BufferHubQueue::kMaxQueueCapacity),
+ epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
available_buffers_(BufferHubQueue::kMaxQueueCapacity),
capacity_(0) {
Initialize();
@@ -101,31 +105,12 @@ bool BufferHubQueue::WaitForBuffers(int timeout) {
ALOGD("New BufferHubQueue event %d: index=%" PRId64, i, index);
- if (is_buffer_event_index(index) && (events[i].events & EPOLLIN)) {
- auto buffer = buffers_[index];
- ret = OnBufferReady(buffer);
- if (ret < 0) {
- ALOGE("Failed to set buffer ready: %s", strerror(-ret));
- continue;
- }
- Enqueue(buffer, index);
- } else if (is_buffer_event_index(index) &&
- (events[i].events & EPOLLHUP)) {
- // This maybe caused by producer replacing an exising buffer slot.
- // Currently the epoll FD is cleaned up when the replacement consumer
- // client is imported.
- ALOGW("Receives EPOLLHUP at slot: %" PRId64, index);
- } else if (is_queue_event_index(index) && (events[i].events & EPOLLIN)) {
- // Note that after buffer imports, if |count()| still returns 0, epoll
- // wait will be tried again to acquire the newly imported buffer.
- ret = OnBufferAllocated();
- if (ret < 0) {
- ALOGE("Failed to import buffer: %s", strerror(-ret));
- continue;
- }
+ if (is_buffer_event_index(index)) {
+ HandleBufferEvent(static_cast<size_t>(index), events[i]);
+ } else if (is_queue_event_index(index)) {
+ HandleQueueEvent(events[i]);
} else {
- ALOGW("Unknown event %d: u64=%" PRId64 ": events=%" PRIu32, i, index,
- events[i].events);
+ ALOGW("Unknown event index: %" PRId64, index);
}
}
}
@@ -133,6 +118,68 @@ bool BufferHubQueue::WaitForBuffers(int timeout) {
return true;
}
+void BufferHubQueue::HandleBufferEvent(size_t slot, const epoll_event& event) {
+ auto buffer = buffers_[slot];
+ if (!buffer) {
+ ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot);
+ return;
+ }
+
+ auto status = buffer->GetEventMask(event.events);
+ if (!status) {
+ ALOGW("BufferHubQueue::HandleBufferEvent: Failed to get event mask: %s",
+ status.GetErrorMessage().c_str());
+ return;
+ }
+
+ int events = status.get();
+ if (events & EPOLLIN) {
+ int ret = OnBufferReady(buffer);
+ if (ret < 0) {
+ ALOGE("Failed to set buffer ready: %s", strerror(-ret));
+ return;
+ }
+ Enqueue(buffer, slot);
+ } else if (events & EPOLLHUP) {
+ // This might be caused by producer replacing an existing buffer slot, or
+ // when BufferHubQueue is shutting down. For the first case, currently the
+ // epoll FD is cleaned up when the replacement consumer client is imported,
+ // we shouldn't detach again if |epollhub_pending_[slot]| is set.
+ ALOGW(
+ "Receives EPOLLHUP at slot: %zu, buffer event fd: %d, EPOLLHUP "
+ "pending: %d",
+ slot, buffer->event_fd(), epollhup_pending_[slot]);
+ if (epollhup_pending_[slot]) {
+ epollhup_pending_[slot] = false;
+ } else {
+ DetachBuffer(slot);
+ }
+ } else {
+ ALOGW("Unknown event, slot=%zu, epoll events=%d", slot, events);
+ }
+}
+
+void BufferHubQueue::HandleQueueEvent(const epoll_event& event) {
+ auto status = GetEventMask(event.events);
+ if (!status) {
+ ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s",
+ status.GetErrorMessage().c_str());
+ return;
+ }
+
+ int events = status.get();
+ if (events & EPOLLIN) {
+ // Note that after buffer imports, if |count()| still returns 0, epoll
+ // wait will be tried again to acquire the newly imported buffer.
+ int ret = OnBufferAllocated();
+ if (ret < 0) {
+ ALOGE("Failed to import buffer: %s", strerror(-ret));
+ }
+ } else {
+ ALOGW("Unknown epoll events=%d", events);
+ }
+}
+
int BufferHubQueue::AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf,
size_t slot) {
if (is_full()) {
@@ -146,8 +193,9 @@ int BufferHubQueue::AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf,
if (buffers_[slot] != nullptr) {
// Replace the buffer if the slot is preoccupied. This could happen when the
// producer side replaced the slot with a newly allocated buffer. Detach the
- // buffer and set up with the new one.
+ // buffer before setting up with the new one.
DetachBuffer(slot);
+ epollhup_pending_[slot] = true;
}
epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u64 = slot}};
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
index 1ea39946e3..02bca09c74 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
@@ -1,5 +1,7 @@
#include "include/private/dvr/buffer_hub_queue_consumer.h"
+//#define LOG_NDEBUG 0
+
namespace android {
namespace dvr {
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
index a108042d01..b013c85b0b 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
@@ -1,5 +1,8 @@
#include "include/private/dvr/buffer_hub_queue_core.h"
+//#define LOG_NDEBUG 0
+#define LOG_TAG "BufferHubQueueCore"
+
#include <log/log.h>
namespace android {
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 752e8c41f0..7ddf49bc7a 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -1,5 +1,7 @@
#include "include/private/dvr/buffer_hub_queue_producer.h"
+//#define LOG_NDEBUG 0
+
#include <inttypes.h>
#include <log/log.h>
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index 83e77d4195..1f2830a1df 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -49,6 +49,14 @@ class BufferHubQueue : public pdx::Client {
return buffers_[slot];
}
+ Status<int> GetEventMask(int events) {
+ if (auto* client_channel = GetChannel()) {
+ return client_channel->GetEventMask(events);
+ } else {
+ return pdx::ErrorStatus(EINVAL);
+ }
+ }
+
// Enqueue a buffer marks buffer to be available (|Gain|'ed for producer
// and |Acquire|'ed for consumer. This is only used for internal bookkeeping.
void Enqueue(std::shared_ptr<BufferHubBuffer> buf, size_t slot);
@@ -87,6 +95,9 @@ class BufferHubQueue : public pdx::Client {
// Wait for buffers to be released and re-add them to the queue.
bool WaitForBuffers(int timeout);
+ void HandleBufferEvent(size_t slot, const epoll_event& event);
+ void HandleQueueEvent(const epoll_event& event);
+
virtual int OnBufferReady(std::shared_ptr<BufferHubBuffer> buf) = 0;
// Called when a buffer is allocated remotely.
@@ -160,6 +171,30 @@ class BufferHubQueue : public pdx::Client {
// |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|.
std::vector<std::shared_ptr<BufferHubBuffer>> buffers_;
+ // |epollhup_pending_| tracks whether a slot of |buffers_| get detached before
+ // its corresponding EPOLLHUP event got handled. This could happen as the
+ // following sequence:
+ // 1. Producer queue's client side allocates a new buffer (at slot 1).
+ // 2. Producer queue's client side replaces an existing buffer (at slot 0).
+ // This is implemented by first detaching the buffer and then allocating a
+ // new buffer.
+ // 3. During the same epoll_wait, Consumer queue's client side gets EPOLLIN
+ // event on the queue which indicates a new buffer is avaiable and the
+ // EPOLLHUP event for slot 0. Consumer handles these two events in order.
+ // 4. Consumer client calls BufferHubRPC::ConsumerQueueImportBuffers and both
+ // slot 0 and (the new) slot 1 buffer will be imported. During the import
+ // of the buffer at slot 1, consuemr client detaches the old buffer so that
+ // the new buffer can be registered. At the same time
+ // |epollhup_pending_[slot]| is marked to indicate that buffer at this slot
+ // was detached prior to EPOLLHUP event.
+ // 5. Consumer client continues to handle the EPOLLHUP. Since
+ // |epollhup_pending_[slot]| is marked as true, it can safely ignore the
+ // event without detaching the newly allocated buffer at slot 1.
+ //
+ // In normal situations where the previously described sequence doesn't
+ // happen, an EPOLLHUP event should trigger a regular buffer detach.
+ std::vector<bool> epollhup_pending_;
+
// |available_buffers_| uses |dvr::RingBuffer| to implementation queue
// sematics. When |Dequeue|, we pop the front element from
// |available_buffers_|, and that buffer's reference count will decrease by
@@ -225,7 +260,7 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> {
// Returns Zero on success and negative error code when buffer allocation
// fails.
int AllocateBuffer(int width, int height, int format, int usage,
- size_t buffer_count, size_t* out_slot);
+ size_t slice_count, size_t* out_slot);
// Add a producer buffer to populate the queue. Once added, a producer buffer
// is available to use (i.e. in |Gain|'ed mode).
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
index 8fd3627d80..fe186198cd 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdisplay/display_manager_client.cpp
@@ -98,14 +98,9 @@ bool dvrDisplayManagerClientSurfaceListGetClientIsVisible(
int dvrDisplayManagerClientGetSurfaceBuffers(
DvrDisplayManagerClient* client, int surface_id,
DvrDisplayManagerClientSurfaceBuffers** surface_buffers) {
- std::vector<std::unique_ptr<android::dvr::BufferConsumer>> buffer_list;
- int ret = client->client->GetSurfaceBuffers(surface_id, &buffer_list);
- if (ret < 0)
- return ret;
-
- *surface_buffers =
- new DvrDisplayManagerClientSurfaceBuffers(std::move(buffer_list));
- return ret;
+ // TODO(jwcai, hendrikw) Remove this after we replacing
+ // dvrDisplayManagerClientGetSurfaceBuffers is dvr_api.
+ return -1;
}
void dvrDisplayManagerClientSurfaceBuffersDestroy(
diff --git a/libs/vr/libdisplay/display_manager_client_impl.cpp b/libs/vr/libdisplay/display_manager_client_impl.cpp
index 82198b92c9..3fbd1e09ef 100644
--- a/libs/vr/libdisplay/display_manager_client_impl.cpp
+++ b/libs/vr/libdisplay/display_manager_client_impl.cpp
@@ -31,27 +31,5 @@ int DisplayManagerClient::GetSurfaceList(
return 0;
}
-int DisplayManagerClient::GetSurfaceBuffers(
- int surface_id, std::vector<std::unique_ptr<BufferConsumer>>* consumers) {
- auto status =
- InvokeRemoteMethod<DisplayManagerRPC::GetSurfaceBuffers>(surface_id);
- if (!status) {
- ALOGE(
- "DisplayManagerClient::GetSurfaceBuffers: Failed to get buffers for "
- "surface_id=%d: %s",
- surface_id, status.GetErrorMessage().c_str());
- return -status.error();
- }
-
- std::vector<std::unique_ptr<BufferConsumer>> consumer_buffers;
- std::vector<LocalChannelHandle> channel_handles = status.take();
- for (auto&& handle : channel_handles) {
- consumer_buffers.push_back(BufferConsumer::Import(std::move(handle)));
- }
-
- *consumers = std::move(consumer_buffers);
- return 0;
-}
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
index 8ba9175f28..f515b8feca 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
@@ -62,10 +62,8 @@ int dvrDisplayManagerClientSurfaceListGetClientZOrder(
bool dvrDisplayManagerClientSurfaceListGetClientIsVisible(
DvrDisplayManagerClientSurfaceList* surface_list, size_t index);
-// Populates |surface_buffers| with the list of buffers for |surface_id|.
-// |surface_id| should be a valid ID from the list of surfaces.
-//
-// @return Returns 0 on success. Otherwise it returns a negative error value.
+// TODO(jwcai, hendrikw) Remove this after we replacing
+// dvrDisplayManagerClientGetSurfaceBuffers is dvr_api.
int dvrDisplayManagerClientGetSurfaceBuffers(
DvrDisplayManagerClient* client, int surface_id,
DvrDisplayManagerClientSurfaceBuffers** surface_buffers);
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
index 4ecd8d4fc0..0897126ce9 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
@@ -17,9 +17,6 @@ class DisplayManagerClient : public pdx::ClientBase<DisplayManagerClient> {
int GetSurfaceList(std::vector<DisplaySurfaceInfo>* surface_list);
- int GetSurfaceBuffers(
- int surface_id, std::vector<std::unique_ptr<BufferConsumer>>* consumers);
-
using Client::event_fd;
using Client::GetChannel;
diff --git a/libs/vr/libdisplay/include/private/dvr/display_rpc.h b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
index 1c1a5e0467..d37aed7d63 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
@@ -258,7 +258,6 @@ struct DisplayManagerRPC {
// Op codes.
enum {
kOpGetSurfaceList = 0,
- kOpGetSurfaceBuffers,
kOpUpdateSurfaces,
};
@@ -269,8 +268,6 @@ struct DisplayManagerRPC {
// Methods.
PDX_REMOTE_METHOD(GetSurfaceList, kOpGetSurfaceList,
std::vector<DisplaySurfaceInfo>(Void));
- PDX_REMOTE_METHOD(GetSurfaceBuffers, kOpGetSurfaceBuffers,
- std::vector<LocalChannelHandle>(int surface_id));
PDX_REMOTE_METHOD(
UpdateSurfaces, kOpUpdateSurfaces,
int(const std::map<int, DisplaySurfaceAttributes>& updates));
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index 6730ba8cd0..6df1642b8e 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -77,11 +77,6 @@ int DisplayManagerService::HandleMessage(pdx::Message& message) {
*this, &DisplayManagerService::OnGetSurfaceList, message);
return 0;
- case DisplayManagerRPC::GetSurfaceBuffers::Opcode:
- DispatchRemoteMethod<DisplayManagerRPC::GetSurfaceBuffers>(
- *this, &DisplayManagerService::OnGetSurfaceBuffers, message);
- return 0;
-
case DisplayManagerRPC::UpdateSurfaces::Opcode:
DispatchRemoteMethod<DisplayManagerRPC::UpdateSurfaces>(
*this, &DisplayManagerService::OnUpdateSurfaces, message);
@@ -128,26 +123,6 @@ std::vector<DisplaySurfaceInfo> DisplayManagerService::OnGetSurfaceList(
return items;
}
-std::vector<LocalChannelHandle> DisplayManagerService::OnGetSurfaceBuffers(
- pdx::Message& message, int surface_id) {
- std::shared_ptr<DisplaySurface> surface =
- display_service_->GetDisplaySurface(surface_id);
- if (!surface)
- REPLY_ERROR_RETURN(message, ENOENT, {});
-
- std::vector<LocalChannelHandle> consumers;
- int ret = surface->GetConsumers(&consumers);
- if (ret < 0) {
- ALOGE(
- "DisplayManagerService::OnGetDisplaySurfaceBuffers: Failed to get "
- "consumers for surface %d: %s",
- surface_id, strerror(-ret));
- REPLY_ERROR_RETURN(message, -ret, {});
- }
-
- return consumers;
-}
-
int DisplayManagerService::OnUpdateSurfaces(
pdx::Message& /*message*/,
const std::map<int, DisplaySurfaceAttributes>& updates) {
diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h
index 46401fa1fc..3f83c7d85d 100644
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ b/libs/vr/libvrflinger/display_manager_service.h
@@ -51,8 +51,6 @@ class DisplayManagerService : public pdx::ServiceBase<DisplayManagerService> {
const std::shared_ptr<DisplayService>& display_service);
std::vector<DisplaySurfaceInfo> OnGetSurfaceList(pdx::Message& message);
- std::vector<pdx::LocalChannelHandle> OnGetSurfaceBuffers(
- pdx::Message& message, int surface_id);
int OnUpdateSurfaces(pdx::Message& message,
const std::map<int, DisplaySurfaceAttributes>& updates);
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 7c821bfd68..d427ea6b10 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -84,22 +84,6 @@ void DisplaySurface::ClientSetBlurBehind(bool blur_behind) {
client_blur_behind_ = blur_behind;
}
-size_t DisplaySurface::GetBufferCount() const {
- std::lock_guard<std::mutex> autolock(lock_);
- return buffers_.size();
-}
-
-std::vector<std::shared_ptr<BufferConsumer>> DisplaySurface::GetBuffers() {
- std::lock_guard<std::mutex> autolock(lock_);
- std::vector<std::shared_ptr<BufferConsumer>> return_vector(buffers_.size());
-
- for (const auto pair : buffers_) {
- return_vector.push_back(pair.second);
- }
-
- return return_vector;
-}
-
AcquiredBuffer DisplaySurface::AcquireNewestAvailableBuffer(
AcquiredBuffer* skipped_buffer) {
std::lock_guard<std::mutex> autolock(lock_);
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index b7bcd973dd..fa34057191 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -65,9 +65,6 @@ class DisplaySurface : public SurfaceChannel {
return buffer_id_to_index_[buffer_id];
}
- size_t GetBufferCount() const;
- std::vector<std::shared_ptr<BufferConsumer>> GetBuffers();
-
// Gets a new set of consumers for all of the surface's buffers. These
// consumers are independent from the consumers maintained internally to the
// surface and may be passed to other processes over IPC.
diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk
index 0f1c925969..ea94bc199f 100644
--- a/opengl/tests/lib/Android.mk
+++ b/opengl/tests/lib/Android.mk
@@ -24,6 +24,7 @@ LOCAL_C_INCLUDES += system/extras/tests/include \
LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
+LOCAL_SHARED_LIBRARIES += libgui
LOCAL_STATIC_LIBRARIES := libarect
include $(BUILD_STATIC_LIBRARY)
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 7bd495fa49..2a17a7f2a1 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -51,7 +51,7 @@ static status_t StatusFromResult(Result result) {
}
}
-SensorDevice::SensorDevice() {
+SensorDevice::SensorDevice() : mHidlTransportErrors(20) {
// SensorDevice may wait upto 100ms * 10 = 1s for hidl service.
constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
size_t retry = 10;
@@ -118,7 +118,15 @@ std::string SensorDevice::dump() const {
if (mSensors == NULL) return "HAL not initialized\n";
String8 result;
- checkReturn(mSensors->getSensorsList([&](const auto &list) {
+
+ result.appendFormat("Saw %d hidlTransport Errors\n", mTotalHidlTransportErrors);
+ for (auto it = mHidlTransportErrors.begin() ; it != mHidlTransportErrors.end(); it++ ) {
+ result += "\t";
+ result += it->toString();
+ result += "\n";
+ }
+
+ checkReturn(mSensors->getSensorsList([&](const auto &list){
const size_t count = list.size();
result.appendFormat(
@@ -182,19 +190,44 @@ ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
if (mSensors == NULL) return NO_INIT;
ssize_t err;
+ int numHidlTransportErrors = 0;
+ bool hidlTransportError = false;
- checkReturn(mSensors->poll(
- count,
- [&](auto result,
- const auto &events,
- const auto &dynamicSensorsAdded) {
- if (result == Result::OK) {
- convertToSensorEvents(events, dynamicSensorsAdded, buffer);
- err = (ssize_t)events.size();
- } else {
- err = StatusFromResult(result);
- }
- }));
+ do {
+ auto ret = mSensors->poll(
+ count,
+ [&](auto result,
+ const auto &events,
+ const auto &dynamicSensorsAdded) {
+ if (result == Result::OK) {
+ convertToSensorEvents(events, dynamicSensorsAdded, buffer);
+ err = (ssize_t)events.size();
+ } else {
+ err = StatusFromResult(result);
+ }
+ });
+
+ if (ret.isOk()) {
+ hidlTransportError = false;
+ } else {
+ hidlTransportError = true;
+ numHidlTransportErrors++;
+ if (numHidlTransportErrors > 50) {
+ // Log error and bail
+ ALOGE("Max Hidl transport errors this cycle : %d", numHidlTransportErrors);
+ handleHidlDeath(ret.description());
+ } else {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+ } while (hidlTransportError);
+
+ if(numHidlTransportErrors > 0) {
+ ALOGE("Saw %d Hidl transport failures", numHidlTransportErrors);
+ HidlTransportErrorLog errLog(time(NULL), numHidlTransportErrors);
+ mHidlTransportErrors.add(errLog);
+ mTotalHidlTransportErrors++;
+ }
return err;
}
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 03552f6d24..410531be6e 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -31,6 +31,8 @@
#include "android/hardware/sensors/1.0/ISensors.h"
+#include "RingBuffer.h"
+
// ---------------------------------------------------------------------------
namespace android {
@@ -41,6 +43,33 @@ using hardware::Return;
class SensorDevice : public Singleton<SensorDevice>, public Dumpable {
public:
+
+ class HidlTransportErrorLog {
+ public:
+
+ HidlTransportErrorLog() {
+ mTs = 0;
+ mCount = 0;
+ }
+
+ HidlTransportErrorLog(time_t ts, int count) {
+ mTs = ts;
+ mCount = count;
+ }
+
+ String8 toString() const {
+ String8 result;
+ struct tm *timeInfo = localtime(&mTs);
+ result.appendFormat("%02d:%02d:%02d :: %d", timeInfo->tm_hour, timeInfo->tm_min,
+ timeInfo->tm_sec, mCount);
+ return result;
+ }
+
+ private:
+ time_t mTs; // timestamp of the error
+ int mCount; // number of transport errors observed
+ };
+
ssize_t getSensorList(sensor_t const** list);
void handleDynamicSensorConnection(int handle, bool connected);
@@ -125,6 +154,10 @@ private:
};
DefaultKeyedVector<int, Info> mActivationCount;
+ // Keep track of any hidl transport failures
+ SensorServiceUtil::RingBuffer<HidlTransportErrorLog> mHidlTransportErrors;
+ int mTotalHidlTransportErrors;
+
// Use this vector to determine which client is activated or deactivated.
SortedVector<void *> mDisabledClients;
SensorDevice();
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index 54d815b722..75e8989380 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -17,29 +17,76 @@
#ifndef ANDROID_SENSOR_REGISTRATION_INFO_H
#define ANDROID_SENSOR_REGISTRATION_INFO_H
+#include "SensorServiceUtils.h"
+#include <utils/Thread.h>
+#include <iomanip>
+#include <sstream>
+
namespace android {
class SensorService;
-struct SensorService::SensorRegistrationInfo {
- int32_t mSensorHandle;
- String8 mPackageName;
- bool mActivated;
- int32_t mSamplingRateUs;
- int32_t mMaxReportLatencyUs;
- int32_t mHour, mMin, mSec;
-
+class SensorService::SensorRegistrationInfo : public SensorServiceUtil::Dumpable {
+public:
SensorRegistrationInfo() : mPackageName() {
mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN;
- mHour = mMin = mSec = INT32_MIN;
+ mHour = mMin = mSec = INT8_MIN;
mActivated = false;
}
+ SensorRegistrationInfo(int32_t handle, const String8 &packageName,
+ int32_t samplingRateNs, int32_t maxReportLatencyNs, bool activate) {
+ mSensorHandle = handle;
+ mPackageName = packageName;
+
+ mSamplingRateUs = static_cast<int32_t>(samplingRateNs/1000);
+ mMaxReportLatencyUs = static_cast<int32_t>(maxReportLatencyNs/1000);
+ mActivated = activate;
+
+ IPCThreadState *thread = IPCThreadState::self();
+ mPid = (thread != nullptr) ? thread->getCallingPid() : -1;
+ mUid = (thread != nullptr) ? thread->getCallingUid() : -1;
+
+ time_t rawtime = time(NULL);
+ struct tm * timeinfo = localtime(&rawtime);
+ mHour = static_cast<int8_t>(timeinfo->tm_hour);
+ mMin = static_cast<int8_t>(timeinfo->tm_min);
+ mSec = static_cast<int8_t>(timeinfo->tm_sec);
+ }
+
static bool isSentinel(const SensorRegistrationInfo& info) {
- return (info.mHour == INT32_MIN &&
- info.mMin == INT32_MIN &&
- info.mSec == INT32_MIN);
+ return (info.mHour == INT8_MIN &&
+ info.mMin == INT8_MIN &&
+ info.mSec == INT8_MIN);
+ }
+
+ // Dumpable interface
+ virtual std::string dump() const override {
+ std::ostringstream ss;
+ ss << std::setfill('0') << std::setw(2) << static_cast<int>(mHour) << ":"
+ << std::setw(2) << static_cast<int>(mMin) << ":"
+ << std::setw(2) << static_cast<int>(mSec)
+ << (mActivated ? " +" : " -")
+ << " 0x" << std::hex << std::setw(8) << mSensorHandle << std::dec
+ << std::setfill(' ') << " pid=" << std::setw(5) << mPid
+ << " uid=" << std::setw(5) << mUid << " package=" << mPackageName;
+ if (mActivated) {
+ ss << " samplingPeriod=" << mSamplingRateUs << "us"
+ << " batchingPeriod=" << mMaxReportLatencyUs << "us";
+ };
+ return ss.str();
}
+
+private:
+ int32_t mSensorHandle;
+ String8 mPackageName;
+ pid_t mPid;
+ uid_t mUid;
+ int32_t mSamplingRateUs;
+ int32_t mMaxReportLatencyUs;
+ bool mActivated;
+ int8_t mHour, mMin, mSec;
+
};
} // namespace android;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c11df13c8a..8fc49214d0 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -480,17 +480,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) {
SENSOR_REGISTRATIONS_BUF_SIZE;
continue;
}
- if (reg_info.mActivated) {
- result.appendFormat("%02d:%02d:%02d activated handle=0x%08x "
- "samplingRate=%dus maxReportLatency=%dus package=%s\n",
- reg_info.mHour, reg_info.mMin, reg_info.mSec, reg_info.mSensorHandle,
- reg_info.mSamplingRateUs, reg_info.mMaxReportLatencyUs,
- reg_info.mPackageName.string());
- } else {
- result.appendFormat("%02d:%02d:%02d de-activated handle=0x%08x package=%s\n",
- reg_info.mHour, reg_info.mMin, reg_info.mSec,
- reg_info.mSensorHandle, reg_info.mPackageName.string());
- }
+ result.appendFormat("%s\n", reg_info.dump().c_str());
currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
SENSOR_REGISTRATIONS_BUF_SIZE;
} while(startIndex != currentIndex);
@@ -1220,18 +1210,10 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection,
if (err == NO_ERROR) {
connection->updateLooperRegistration(mLooper);
- SensorRegistrationInfo &reg_info =
- mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex);
- reg_info.mSensorHandle = handle;
- reg_info.mSamplingRateUs = samplingPeriodNs/1000;
- reg_info.mMaxReportLatencyUs = maxBatchReportLatencyNs/1000;
- reg_info.mActivated = true;
- reg_info.mPackageName = connection->getPackageName();
- time_t rawtime = time(NULL);
- struct tm * timeinfo = localtime(&rawtime);
- reg_info.mHour = timeinfo->tm_hour;
- reg_info.mMin = timeinfo->tm_min;
- reg_info.mSec = timeinfo->tm_sec;
+
+ mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) =
+ SensorRegistrationInfo(handle, connection->getPackageName(),
+ samplingPeriodNs, maxBatchReportLatencyNs, true);
mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
}
@@ -1254,16 +1236,8 @@ status_t SensorService::disable(const sp<SensorEventConnection>& connection, int
}
if (err == NO_ERROR) {
- SensorRegistrationInfo &reg_info =
- mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex);
- reg_info.mActivated = false;
- reg_info.mPackageName= connection->getPackageName();
- reg_info.mSensorHandle = handle;
- time_t rawtime = time(NULL);
- struct tm * timeinfo = localtime(&rawtime);
- reg_info.mHour = timeinfo->tm_hour;
- reg_info.mMin = timeinfo->tm_min;
- reg_info.mSec = timeinfo->tm_sec;
+ mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) =
+ SensorRegistrationInfo(handle, connection->getPackageName(), 0, 0, false);
mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
}
return err;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 5583dad53f..d0be121cd9 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -91,7 +91,7 @@ private:
// nested class/struct for internal use
class SensorRecord;
class SensorEventAckReceiver;
- struct SensorRegistrationInfo;
+ class SensorRegistrationInfo;
enum Mode {
// The regular operating mode where any application can register/unregister/call flush on
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 5ea3445c10..d325e4d880 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -77,12 +77,6 @@ ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true)
LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK
endif
-ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
- LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS)
-else
- LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=0
-endif
-
ifneq ($(MAX_VIRTUAL_DISPLAY_DIMENSION),)
LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=$(MAX_VIRTUAL_DISPLAY_DIMENSION)
else
@@ -166,6 +160,7 @@ LOCAL_SHARED_LIBRARIES := \
libbinder \
libutils \
libui \
+ libgui \
libdl
LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
@@ -204,3 +199,5 @@ LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
include $(BUILD_SHARED_LIBRARY)
endif # libnativehelper
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 86cf17d61a..d7654f1034 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -33,6 +33,7 @@
#include <ui/Fence.h>
#include "DispSync.h"
+#include "SurfaceFlinger.h"
#include "EventLog/EventLog.h"
using std::max;
@@ -54,10 +55,6 @@ static const bool kEnableZeroPhaseTracer = false;
// present time and the nearest software-predicted vsync.
static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared
-// This is the offset from the present fence timestamps to the corresponding
-// vsync event.
-static const int64_t kPresentTimeOffset = PRESENT_TIME_OFFSET_FROM_VSYNC_NS;
-
#undef LOG_TAG
#define LOG_TAG "DispSyncThread"
class DispSyncThread: public Thread {
@@ -381,6 +378,7 @@ DispSync::DispSync(const char* name) :
mRefreshSkipCount(0),
mThread(new DispSyncThread(name)) {
+ mPresentTimeOffset = SurfaceFlinger::dispSyncPresentTimeOffset;
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
// set DispSync to SCHED_FIFO to minimize jitter
struct sched_param param = {0};
@@ -433,7 +431,7 @@ bool DispSync::addPresentFence(const sp<Fence>& fence) {
nsecs_t t = f->getSignalTime();
if (t < INT64_MAX) {
mPresentFences[i].clear();
- mPresentTimes[i] = t + kPresentTimeOffset;
+ mPresentTimes[i] = t + mPresentTimeOffset;
}
}
}
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 2763e59559..5b7083d987 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -182,6 +182,10 @@ private:
// mMutex is used to protect access to all member variables.
mutable Mutex mMutex;
+
+ // This is the offset from the present fence timestamps to the corresponding
+ // vsync event.
+ int64_t mPresentTimeOffset;
};
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3677c2e09d..d5112d29e4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -112,6 +112,7 @@ const String16 sDump("android.permission.DUMP");
int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
bool SurfaceFlinger::useContextPriority;
+int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
@@ -167,6 +168,9 @@ SurfaceFlinger::SurfaceFlinger()
useContextPriority = getBool< ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::useContextPriority>(false);
+ dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);
+
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -3221,11 +3225,10 @@ void SurfaceFlinger::appendSfConfigString(String8& result) const
result.append(" [sf");
result.appendFormat(" HAS_CONTEXT_PRIORITY=%d", useContextPriority);
-#ifdef NEVER_DEFAULT_TO_ASYNC_MODE
- result.append(" NEVER_DEFAULT_TO_ASYNC_MODE");
-#endif
if (isLayerTripleBufferingDisabled())
result.append(" DISABLE_TRIPLE_BUFFERING");
+
+ result.appendFormat(" PRESENT_TIME_OFFSET=%" PRId64 , dispSyncPresentTimeOffset);
result.append("]");
}
@@ -3352,9 +3355,9 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
result.append("DispSync configuration: ");
colorizer.reset(result);
result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
- "present offset %d ns (refresh %" PRId64 " ns)",
+ "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
- PRESENT_TIME_OFFSET_FROM_VSYNC_NS, activeConfig->getVsyncPeriod());
+ dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
result.append("\n");
// Dump static screen stats
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 11d7c6ffd7..c36dd68e32 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -131,6 +131,10 @@ public:
// Instruct the Render Engine to use EGL_IMG_context_priority is available.
static bool useContextPriority;
+ // The offset in nanoseconds to use when DispSync timestamps present fence
+ // signaling time.
+ static int64_t dispSyncPresentTimeOffset;
+
static char const* getServiceName() ANDROID_API {
return "SurfaceFlinger";
}
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 01226e0abd..1d2b485164 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -179,7 +179,7 @@ nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync)
const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
// The DispSync time is already adjusted for the difference between
- // vsync and reported-vsync (PRESENT_TIME_OFFSET_FROM_VSYNC_NS), so
+ // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
// we don't need to factor that in here. Pad a little to avoid
// weird effects if apps might be requesting times right on the edge.
nsecs_t extraPadding = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index f37fa6c16c..e767e51bab 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -111,6 +111,7 @@ const String16 sDump("android.permission.DUMP");
int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
bool SurfaceFlinger::useContextPriority;
+int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
@@ -158,6 +159,9 @@ SurfaceFlinger::SurfaceFlinger()
useContextPriority = getBool< ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::useContextPriority>(false);
+ dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);
+
char value[PROPERTY_VALUE_MAX];
property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
@@ -2993,11 +2997,9 @@ void SurfaceFlinger::appendSfConfigString(String8& result) const
result.append(" [sf");
result.appendFormat(" HAS_CONTEXT_PRIORITY=%d", useContextPriority);
-#ifdef NEVER_DEFAULT_TO_ASYNC_MODE
- result.append(" NEVER_DEFAULT_TO_ASYNC_MODE");
-#endif
if (isLayerTripleBufferingDisabled())
result.append(" DISABLE_TRIPLE_BUFFERING");
+ result.appendFormat(" PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset);
result.append("]");
}
@@ -3121,8 +3123,8 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
result.append("DispSync configuration: ");
colorizer.reset(result);
result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
- "present offset %d ns (refresh %" PRId64 " ns)",
- vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
+ "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+ vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, dispSyncPresentTimeOffset,
mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
result.append("\n");
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index f93d91881a..f46ce8af97 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -8,8 +8,9 @@ LOCAL_MODULE := SurfaceFlinger_test
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
- Transaction_test.cpp \
- SurfaceInterceptor_test.cpp
+ Transaction_test.cpp \
+ Stress_test.cpp \
+ SurfaceInterceptor_test.cpp
LOCAL_SHARED_LIBRARIES := \
libEGL \
@@ -20,6 +21,7 @@ LOCAL_SHARED_LIBRARIES := \
libprotobuf-cpp-full \
libui \
libutils \
+ libandroid \
liblog
LOCAL_STATIC_LIBRARIES := libtrace_proto
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
new file mode 100644
index 0000000000..33dd2f55d3
--- /dev/null
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <gui/SurfaceComposerClient.h>
+
+#include <utils/String8.h>
+
+#include <thread>
+#include <functional>
+
+
+namespace android {
+
+TEST(SurfaceFlingerStress, create_and_destroy) {
+ auto do_stress = []() {
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, client->initCheck());
+ for (int j = 0; j < 1000; j++) {
+ auto surf = client->createSurface(String8("t"), 100, 100,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(surf != nullptr);
+ client->destroySurface(surf->getHandle());
+ }
+ };
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 10; i++) {
+ threads.push_back(std::thread(do_stress));
+ }
+ for (auto& thread : threads) {
+ thread.join();
+ }
+}
+
+}
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 1a3f89f272..0cc763c740 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -15,6 +15,7 @@
*/
#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <gtest/gtest.h>
@@ -68,11 +69,18 @@ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g,
}
static status_t readProtoFile(Trace* trace) {
- std::ifstream input(DEFAULT_FILENAME, std::ios::in | std::ios::binary);
- if (input && !trace->ParseFromIstream(&input)) {
- return PERMISSION_DENIED;
+ status_t err = NO_ERROR;
+
+ int fd = open(DEFAULT_FILENAME, O_RDONLY);
+ {
+ google::protobuf::io::FileInputStream f(fd);
+ if (fd && !trace->ParseFromZeroCopyStream(&f)) {
+ err = PERMISSION_DENIED;
+ }
}
- return NO_ERROR;
+ close(fd);
+
+ return err;
}
static void enableInterceptor() {
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp
index 39d6bc8cae..ae87acd1d8 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.cpp
+++ b/services/vr/bufferhubd/consumer_queue_channel.cpp
@@ -92,29 +92,39 @@ ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) {
size_t producer_slot = pending_buffer_slots_.front().second;
pending_buffer_slots_.pop();
- // It's possible that the producer channel has expired.
+ // It's possible that the producer channel has expired. When this occurs,
+ // ignore the producer channel.
if (producer_channel == nullptr) {
- ALOGE(
+ ALOGW(
"ConsumerQueueChannel::OnConsumerQueueImportBuffers: producer "
"channel has already been expired.");
- REPLY_ERROR_RETURN(message, ENOENT, {});
+ continue;
}
RemoteChannelHandle consumer_handle(
producer_channel->CreateConsumer(message));
- // All buffer imports should succeed together.
+ // If no buffers are imported successfully, clear available and return an
+ // error. Otherwise, return all consumer handles already imported
+ // successfully, but keep available bits on, so that the client can retry
+ // importing remaining consumer buffers.
if (!consumer_handle.valid()) {
ALOGE(
"ConsumerQueueChannel::OnConsumerQueueImportBuffers: imported "
"consumer handle is invalid.");
- REPLY_ERROR_RETURN(message, EIO, {});
+ if (buffer_handles.empty()) {
+ ClearAvailable();
+ REPLY_ERROR_RETURN(message, EIO, {});
+ } else {
+ return buffer_handles;
+ }
}
// Move consumer_handle into buffer_handles.
buffer_handles.emplace_back(std::move(consumer_handle), producer_slot);
}
+ ClearAvailable();
return buffer_handles;
}
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index ba3cf791e4..3f077a249c 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -16,7 +16,10 @@ ndk_headers {
name: "libvulkan_headers",
from: "include",
to: "",
- srcs: ["include/vulkan/**/*.h"],
+ srcs: [
+ "include/vulkan/vk_platform.h",
+ "include/vulkan/vulkan.h",
+ ],
license: "include/vulkan/NOTICE",
}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 47404d59e4..7e96b4cf2f 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -17,7 +17,7 @@
#include <algorithm>
#include <log/log.h>
-#include <gui/BufferQueue.h>
+#include <ui/BufferQueueDefs.h>
#include <sync/sync.h>
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
@@ -207,7 +207,7 @@ struct Swapchain {
// or by passing ownership e.g. to ANativeWindow::cancelBuffer().
int dequeue_fence;
bool dequeued;
- } images[android::BufferQueue::NUM_BUFFER_SLOTS];
+ } images[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
android::Vector<TimingInfo> timing;
};
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index e03ee0a27a..67147791f3 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -513,6 +513,28 @@ void GetPhysicalDeviceProperties(VkPhysicalDevice,
void GetPhysicalDeviceProperties2KHR(VkPhysicalDevice physical_device,
VkPhysicalDeviceProperties2KHR* properties) {
GetPhysicalDeviceProperties(physical_device, &properties->properties);
+
+ while (properties->pNext) {
+ properties = reinterpret_cast<VkPhysicalDeviceProperties2KHR *>(properties->pNext);
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+ switch ((VkFlags)properties->sType) {
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID: {
+ VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties =
+ reinterpret_cast<VkPhysicalDevicePresentationPropertiesANDROID *>(properties);
+#pragma clang diagnostic pop
+
+ // Claim that we do all the right things for the loader to
+ // expose KHR_shared_presentable_image on our behalf.
+ presentation_properties->sharedImage = VK_TRUE;
+ } break;
+
+ default:
+ // Silently ignore other extension query structs
+ break;
+ }
+ }
}
void GetPhysicalDeviceQueueFamilyProperties(