Use RAII for locking/unlocking buffers.
Bug: 324383963
Test: atest virtual_camera_tests
Test: atest VirtualCameraTest
Change-Id: I8d8071250f7847334a75e261c7f69b5022e04507
diff --git a/services/camera/virtualcamera/util/Util.cc b/services/camera/virtualcamera/util/Util.cc
index ef986a6..b2048bc 100644
--- a/services/camera/virtualcamera/util/Util.cc
+++ b/services/camera/virtualcamera/util/Util.cc
@@ -20,8 +20,13 @@
#include <algorithm>
#include <array>
+#include <cstdint>
+#include <memory>
+#include "android/hardware_buffer.h"
#include "jpeglib.h"
+#include "ui/GraphicBuffer.h"
+#include "utils/Errors.h"
namespace android {
namespace companion {
@@ -40,6 +45,82 @@
constexpr std::array<Format, 2> kSupportedFormats{Format::YUV_420_888,
Format::RGBA_8888};
+YCbCrLockGuard::YCbCrLockGuard(std::shared_ptr<AHardwareBuffer> hwBuffer,
+ const uint32_t usageFlags)
+ : mHwBuffer(hwBuffer) {
+ GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(mHwBuffer.get());
+ if (gBuffer == nullptr) {
+ ALOGE("%s: Attempting to lock nullptr buffer.", __func__);
+ return;
+ }
+ mLockStatus = gBuffer->lockYCbCr(usageFlags, &mYCbCr);
+ if (mLockStatus != OK) {
+ ALOGE("%s: Failed to lock graphic buffer: %s", __func__,
+ statusToString(mLockStatus).c_str());
+ }
+}
+
+YCbCrLockGuard::~YCbCrLockGuard() {
+ if (getStatus() != OK) {
+ return;
+ }
+
+ GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(mHwBuffer.get());
+ if (gBuffer == nullptr) {
+ return;
+ }
+ gBuffer->unlock();
+ status_t status = gBuffer->unlock();
+ if (status != NO_ERROR) {
+ ALOGE("Failed to unlock graphic buffer: %s", statusToString(status).c_str());
+ }
+}
+
+status_t YCbCrLockGuard::getStatus() const {
+ return mLockStatus;
+}
+
+const android_ycbcr& YCbCrLockGuard::operator*() const {
+ LOG_ALWAYS_FATAL_IF(getStatus() != OK,
+ "Dereferencing unlocked YCbCrLockGuard, status is %s",
+ statusToString(mLockStatus).c_str());
+ return mYCbCr;
+}
+
+PlanesLockGuard::PlanesLockGuard(std::shared_ptr<AHardwareBuffer> hwBuffer,
+ const uint64_t usageFlags, sp<Fence> fence) {
+ if (hwBuffer == nullptr) {
+ ALOGE("%s: Attempting to lock nullptr buffer.", __func__);
+ return;
+ }
+
+ const int32_t rawFence = fence != nullptr ? fence->get() : -1;
+ mLockStatus = static_cast<status_t>(AHardwareBuffer_lockPlanes(
+ hwBuffer.get(), usageFlags, rawFence, nullptr, &mPlanes));
+ if (mLockStatus != OK) {
+ ALOGE("%s: Failed to lock graphic buffer: %s", __func__,
+ statusToString(mLockStatus).c_str());
+ }
+}
+
+PlanesLockGuard::~PlanesLockGuard() {
+ if (getStatus() != OK || mHwBuffer == nullptr) {
+ return;
+ }
+ AHardwareBuffer_unlock(mHwBuffer.get(), /*fence=*/nullptr);
+}
+
+int PlanesLockGuard::getStatus() const {
+ return mLockStatus;
+}
+
+const AHardwareBuffer_Planes& PlanesLockGuard::operator*() const {
+ LOG_ALWAYS_FATAL_IF(getStatus() != OK,
+ "Dereferencing unlocked PlanesLockGuard, status is %s",
+ statusToString(mLockStatus).c_str());
+ return mPlanes;
+}
+
sp<Fence> importFence(const NativeHandle& aidlHandle) {
if (aidlHandle.fds.size() != 1) {
return sp<Fence>::make();
diff --git a/services/camera/virtualcamera/util/Util.h b/services/camera/virtualcamera/util/Util.h
index 15f7969..d5b0b1f 100644
--- a/services/camera/virtualcamera/util/Util.h
+++ b/services/camera/virtualcamera/util/Util.h
@@ -18,17 +18,80 @@
#define ANDROID_COMPANION_VIRTUALCAMERA_UTIL_H
#include <cstdint>
+#include <memory>
#include "aidl/android/companion/virtualcamera/Format.h"
#include "aidl/android/hardware/camera/common/Status.h"
#include "aidl/android/hardware/camera/device/StreamBuffer.h"
#include "android/binder_auto_utils.h"
+#include "android/hardware_buffer.h"
+#include "system/graphics.h"
#include "ui/Fence.h"
namespace android {
namespace companion {
namespace virtualcamera {
+// RAII utility class to safely lock AHardwareBuffer and obtain android_ycbcr
+// structure describing YUV plane layout.
+//
+// Access to the buffer is locked immediatelly afer construction.
+class YCbCrLockGuard {
+ public:
+ YCbCrLockGuard(std::shared_ptr<AHardwareBuffer> hwBuffer, uint32_t usageFlags);
+ YCbCrLockGuard(YCbCrLockGuard&& other) = default;
+ ~YCbCrLockGuard();
+
+ // Returns OK if the buffer is successfully locked.
+ status_t getStatus() const;
+
+ // Dereferencing instance of this guard returns android_ycbcr structure
+ // describing the layout.
+ // Caller needs to check whether the buffer was successfully locked
+ // before dereferencing.
+ const android_ycbcr& operator*() const;
+
+ // Disable copy.
+ YCbCrLockGuard(const YCbCrLockGuard&) = delete;
+ YCbCrLockGuard& operator=(const YCbCrLockGuard&) = delete;
+
+ private:
+ std::shared_ptr<AHardwareBuffer> mHwBuffer;
+ android_ycbcr mYCbCr = {};
+ status_t mLockStatus = DEAD_OBJECT;
+};
+
+// RAII utility class to safely lock AHardwareBuffer and obtain
+// AHardwareBuffer_Planes (Suitable for interacting with RGBA / BLOB buffers.
+//
+// Access to the buffer is locked immediatelly afer construction.
+class PlanesLockGuard {
+ public:
+ PlanesLockGuard(std::shared_ptr<AHardwareBuffer> hwBuffer,
+ uint64_t usageFlags, sp<Fence> fence = nullptr);
+ PlanesLockGuard(PlanesLockGuard&& other) = default;
+ ~PlanesLockGuard();
+
+ // Returns OK if the buffer is successfully locked.
+ status_t getStatus() const;
+
+ // Dereferencing instance of this guard returns AHardwareBuffer_Planes
+ // structure describing the layout.
+ //
+ // Caller needs to check whether the buffer was successfully locked
+ // before dereferencing.
+ const AHardwareBuffer_Planes& operator*() const;
+
+ // Disable copy.
+ PlanesLockGuard(const PlanesLockGuard&) = delete;
+ PlanesLockGuard& operator=(const YCbCrLockGuard&) = delete;
+
+ private:
+ std::shared_ptr<AHardwareBuffer> mHwBuffer;
+ AHardwareBuffer_Planes mPlanes;
+ status_t mLockStatus = DEAD_OBJECT;
+};
+
// Converts camera AIDL status to ndk::ScopedAStatus
inline ndk::ScopedAStatus cameraStatus(
const ::aidl::android::hardware::camera::common::Status status) {