/* * 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 == nullptr ? nullptr : 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