diff options
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 ®_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 ®_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( |