Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92c7a651 authored by Emilian Peev's avatar Emilian Peev
Browse files

Camera: Add Hal version 1 image capture test cases

Tests involving Hal version 1 image capture APIs are
required. Several cases cover this:
- 'takePicture' - Regular image capture after preview gets enabled.
- 'takePictureFail' - Checks correct behavior in case preview is not
running.
- 'cancelPicture' - Verifies that image capture can be cancelled.
- 'cancelPictureFail' - Checks that image capture cancel fails as
expected in case 'takePicture' didn't get called.
Switch to BufferItemConsumer instead of CpuConsumer and use GLConsumer
default usage flags.

Bug: 32022758
Test: compile and run the gtest binary on device
Change-Id: I8db60aa8a21b6f829574fc9538da5644a4051e49
parent 24f09645
Loading
Loading
Loading
Loading
+263 −59
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@
#include <VtsHalHidlTargetTestBase.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
#include <gui/CpuConsumer.h>
#include <gui/BufferItemConsumer.h>
#include <binder/MemoryHeapBase.h>
#include <regex>
#include "system/camera_metadata.h"
@@ -42,11 +42,12 @@ using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::sp;
using ::android::wp;
using ::android::GraphicBuffer;
using ::android::IGraphicBufferProducer;
using ::android::IGraphicBufferConsumer;
using ::android::BufferQueue;
using ::android::CpuConsumer;
using ::android::BufferItemConsumer;
using ::android::Surface;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
using ::android::hardware::graphics::allocator::V2_0::ProducerUsage;
@@ -187,6 +188,22 @@ void CameraHidlEnvironment::TearDown() {
    ALOGI("TearDown CameraHidlEnvironment");
}

struct BufferItemHander: public BufferItemConsumer::FrameAvailableListener {
    BufferItemHander(wp<BufferItemConsumer> consumer) : mConsumer(consumer) {}

    void onFrameAvailable(const android::BufferItem&) override {
        sp<BufferItemConsumer> consumer = mConsumer.promote();
        ASSERT_NE(nullptr, consumer.get());

        android::BufferItem buffer;
        ASSERT_EQ(android::OK, consumer->acquireBuffer(&buffer, 0));
        ASSERT_EQ(android::OK, consumer->releaseBuffer(buffer));
    }

 private:
    wp<BufferItemConsumer> mConsumer;
};

struct PreviewWindowCb : public ICameraDevicePreviewCallback {
    PreviewWindowCb(sp<ANativeWindow> anw) : mPreviewWidth(0),
            mPreviewHeight(0), mFormat(0), mPreviewUsage(0),
@@ -492,6 +509,12 @@ public:
        CameraHidlTest *mParent;               // Parent object
    };

    void openCameraDevice(const std::string &name,const CameraHidlEnvironment* env,
            sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device /*out*/);
    void setupPreviewWindow(
            const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
            sp<BufferItemConsumer> *bufferItemConsumer /*out*/,
            sp<BufferItemHander> *bufferHandler /*out*/);
    void openEmptyDeviceSession(const std::string &name,
            const CameraHidlEnvironment* env,
            sp<ICameraDeviceSession> *session /*out*/,
@@ -521,6 +544,7 @@ protected:
    uint32_t mResultFrameNumber;               // Expected result frame number
    std::vector<StreamBuffer> mResultBuffers;  // Holds stream buffers from capture result
    std::vector<ErrorMsg> mErrors;             // Holds incoming error notifications
    DataCallbackMsg mDataMessageTypeReceived;  // Most recent message type received through data callbacks

    std::mutex mTorchLock;                     // Synchronize access to torch status
    std::condition_variable mTorchCond;        // Condition variable for torch status
@@ -572,6 +596,10 @@ Return<void> CameraHidlTest::Camera1DeviceCb::dataCallback(
        DataCallbackMsg msgType __unused, uint32_t data __unused,
        uint32_t bufferIndex __unused,
        const CameraFrameMetadata& metadata __unused) {
    std::unique_lock<std::mutex> l(mParent->mLock);
    mParent->mDataMessageTypeReceived = msgType;
    mParent->mResultCondition.notify_one();

    return Void();
}

@@ -918,30 +946,14 @@ TEST_F(CameraHidlTest, startStopPreview) {

    for (const auto& name : cameraDeviceNames) {
        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
            ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
            ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
            env->mProvider->getCameraDeviceInterface_V1_x(
                name,
                [&](auto status, const auto& device) {
                    ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
                    ASSERT_EQ(Status::OK, status);
                    ASSERT_NE(device, nullptr);
                    device1 = device;
                });

            sp<Camera1DeviceCb> deviceCb = new Camera1DeviceCb(this);
            ASSERT_EQ(Status::OK, device1->open(deviceCb));
            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
                    openCameraDevice(name, env, &device1 /*out*/);
            ASSERT_NE(nullptr, device1.get());
            sp<BufferItemConsumer> bufferItemConsumer;
            sp<BufferItemHander> bufferHandler;
            setupPreviewWindow(device1,
                    &bufferItemConsumer /*out*/, &bufferHandler /*out*/);

            sp<IGraphicBufferProducer> producer;
            sp<IGraphicBufferConsumer> consumer;
            BufferQueue::createBufferQueue(&producer, &consumer);
            sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
            sp<Surface> surface = new Surface(producer);
            sp<ANativeWindow> window(surface);

            sp<PreviewWindowCb> previewCb = new PreviewWindowCb(
                    window);
            ASSERT_EQ(Status::OK, device1->setPreviewWindow(previewCb));
            ASSERT_EQ(Status::OK, device1->startPreview());
            ASSERT_TRUE(device1->previewEnabled());
            device1->stopPreview();
@@ -959,32 +971,19 @@ TEST_F(CameraHidlTest, startStopPreviewDelayed) {

    for (const auto& name : cameraDeviceNames) {
        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
            ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
            ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
            env->mProvider->getCameraDeviceInterface_V1_x(
                name,
                [&](auto status, const auto& device) {
                    ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
                    ASSERT_EQ(Status::OK, status);
                    ASSERT_NE(device, nullptr);
                    device1 = device;
                });
            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
            openCameraDevice(name, env, &device1 /*out*/);
            ASSERT_NE(nullptr, device1.get());

            sp<Camera1DeviceCb> deviceCb = new Camera1DeviceCb(this);
            ASSERT_EQ(Status::OK, device1->open(deviceCb));
            ASSERT_EQ(Status::OK, device1->setPreviewWindow(nullptr));
            ASSERT_EQ(Status::OK, device1->startPreview());

            sp<IGraphicBufferProducer> producer;
            sp<IGraphicBufferConsumer> consumer;
            BufferQueue::createBufferQueue(&producer, &consumer);
            sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
            sp<Surface> surface = new Surface(producer);
            sp<ANativeWindow> window(surface);
            sp<PreviewWindowCb> previewCb = new PreviewWindowCb(window);
            sp<BufferItemConsumer> bufferItemConsumer;
            sp<BufferItemHander> bufferHandler;
            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
                    &bufferHandler /*out*/);

            //Preview should get enabled now
            ASSERT_EQ(Status::OK, device1->setPreviewWindow(previewCb));
            ASSERT_TRUE(device1->previewEnabled());
            device1->stopPreview();

@@ -993,6 +992,175 @@ TEST_F(CameraHidlTest, startStopPreviewDelayed) {
    }
}

// Verify that image capture behaves as expected along with preview callbacks.
TEST_F(CameraHidlTest, takePicture) {
    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();

    for (const auto& name : cameraDeviceNames) {
        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
            openCameraDevice(name, env, &device1 /*out*/);
            ASSERT_NE(nullptr, device1.get());
            sp<BufferItemConsumer> bufferItemConsumer;
            sp<BufferItemHander> bufferHandler;
            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
                    &bufferHandler /*out*/);

            {
                std::unique_lock<std::mutex> l(mLock);
                mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
            }

            device1->enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME);
            ASSERT_TRUE(device1->msgTypeEnabled(
                    (unsigned int)DataCallbackMsg::PREVIEW_FRAME));
            ASSERT_EQ(Status::OK, device1->startPreview());

            {
                std::unique_lock<std::mutex> l(mLock);
                while (DataCallbackMsg::PREVIEW_FRAME !=
                        mDataMessageTypeReceived) {
                    auto timeout = std::chrono::system_clock::now() +
                            std::chrono::seconds(kStreamBufferTimeoutSec);
                    ASSERT_NE(std::cv_status::timeout,
                            mResultCondition.wait_until(l, timeout));
                }
            }

            device1->disableMsgType(
                    (unsigned int)DataCallbackMsg::PREVIEW_FRAME);
            ASSERT_FALSE(device1->msgTypeEnabled(
                    (unsigned int)DataCallbackMsg::PREVIEW_FRAME));
            device1->enableMsgType(
                    (unsigned int)DataCallbackMsg::COMPRESSED_IMAGE);
            ASSERT_TRUE(device1->msgTypeEnabled(
                    (unsigned int)DataCallbackMsg::COMPRESSED_IMAGE));

            {
                std::unique_lock<std::mutex> l(mLock);
                mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
            }

            ASSERT_EQ(Status::OK, device1->takePicture());

            {
                std::unique_lock<std::mutex> l(mLock);
                while (DataCallbackMsg::COMPRESSED_IMAGE !=
                        mDataMessageTypeReceived) {
                    auto timeout = std::chrono::system_clock::now() +
                            std::chrono::seconds(kStreamBufferTimeoutSec);
                    ASSERT_NE(std::cv_status::timeout,
                            mResultCondition.wait_until(l, timeout));
                }
            }

            device1->disableMsgType(
                    (unsigned int)DataCallbackMsg::COMPRESSED_IMAGE);
            ASSERT_FALSE(device1->msgTypeEnabled(
                    (unsigned int)DataCallbackMsg::COMPRESSED_IMAGE));

            device1->stopPreview();

            device1->close();
        }
    }
}

// Image capture should fail in case preview didn't get enabled first.
TEST_F(CameraHidlTest, takePictureFail) {
    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();

    for (const auto& name : cameraDeviceNames) {
        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
            openCameraDevice(name, env, &device1 /*out*/);
            ASSERT_NE(nullptr, device1.get());

            ASSERT_NE(Status::OK, device1->takePicture());

            device1->close();
        }
    }
}

// Verify that image capture can be cancelled.
TEST_F(CameraHidlTest, cancelPicture) {
    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();

    for (const auto& name : cameraDeviceNames) {
        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
            openCameraDevice(name, env, &device1 /*out*/);
            ASSERT_NE(nullptr, device1.get());
            sp<BufferItemConsumer> bufferItemConsumer;
            sp<BufferItemHander> bufferHandler;
            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
                    &bufferHandler /*out*/);

            {
                std::unique_lock<std::mutex> l(mLock);
                mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
            }

            device1->enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME);
            ASSERT_TRUE(device1->msgTypeEnabled(
                    (unsigned int)DataCallbackMsg::PREVIEW_FRAME));
            ASSERT_EQ(Status::OK, device1->startPreview());

            {
                std::unique_lock<std::mutex> l(mLock);
                while (DataCallbackMsg::PREVIEW_FRAME !=
                        mDataMessageTypeReceived) {
                    auto timeout = std::chrono::system_clock::now() +
                            std::chrono::seconds(kStreamBufferTimeoutSec);
                    ASSERT_NE(std::cv_status::timeout,
                            mResultCondition.wait_until(l, timeout));
                }
            }

            device1->disableMsgType(
                    (unsigned int)DataCallbackMsg::PREVIEW_FRAME);
            ASSERT_FALSE(device1->msgTypeEnabled(
                    (unsigned int)DataCallbackMsg::PREVIEW_FRAME));

            ASSERT_EQ(Status::OK, device1->takePicture());
            ASSERT_EQ(Status::OK, device1->cancelPicture());

            device1->stopPreview();

            device1->close();
        }
    }
}

// Image capture cancel should fail when image capture is not running.
TEST_F(CameraHidlTest, cancelPictureFail) {
    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();

    for (const auto& name : cameraDeviceNames) {
        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
            openCameraDevice(name, env, &device1 /*out*/);
            ASSERT_NE(nullptr, device1.get());
            sp<BufferItemConsumer> bufferItemConsumer;
            sp<BufferItemHander> bufferHandler;
            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
                    &bufferHandler /*out*/);

            ASSERT_EQ(Status::OK, device1->startPreview());
            ASSERT_NE(Status::OK, device1->cancelPicture());

            device1->stopPreview();

            device1->close();
        }
    }
}

// Verify that the static camera characteristics can be retrieved
// successfully.
TEST_F(CameraHidlTest, getCameraCharacteristics) {
@@ -1098,7 +1266,7 @@ TEST_F(CameraHidlTest, setTorchMode) {
            }
        } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
            ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
            ALOGI("setTorchMode: Testing camera device %s", name.c_str());
            ALOGI("dumpState: Testing camera device %s", name.c_str());
            env->mProvider->getCameraDeviceInterface_V1_x(
                name,
                [&](auto status, const auto& device) {
@@ -1240,18 +1408,9 @@ TEST_F(CameraHidlTest, openClose) {
            // TODO: test all session API calls return INTERNAL_ERROR after close
            // TODO: keep a wp copy here and verify session cannot be promoted out of this scope
        } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
            ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
            ALOGI("openClose: Testing camera device %s", name.c_str());
            env->mProvider->getCameraDeviceInterface_V1_x(
                name,
                [&](auto status, const auto& device) {
                    ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
                    ASSERT_EQ(Status::OK, status);
                    ASSERT_NE(device, nullptr);
                    device1 = device;
                });
            sp<Camera1DeviceCb> cb = new Camera1DeviceCb(this);
            ASSERT_EQ(Status::OK, device1->open(cb));
            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
            openCameraDevice(name, env, &device1 /*out*/);
            ASSERT_NE(nullptr, device1.get());

            native_handle_t* raw_handle = native_handle_create(1, 0);
            raw_handle->data[0] = open(kDumpOutput, O_RDWR);
@@ -2325,6 +2484,51 @@ void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
    });
}

void CameraHidlTest::openCameraDevice(const std::string &name,
        const CameraHidlEnvironment* env,
        sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device1 /*out*/) {
    ASSERT_TRUE(nullptr != env);
    ASSERT_TRUE(nullptr != device1);

    env->mProvider->getCameraDeviceInterface_V1_x(
            name,
            [&](auto status, const auto& device) {
            ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
                  (int)status);
            ASSERT_EQ(Status::OK, status);
            ASSERT_NE(device, nullptr);
            *device1 = device;
        });

    sp<Camera1DeviceCb> deviceCb = new Camera1DeviceCb(this);
    ASSERT_EQ(Status::OK, (*device1)->open(deviceCb));
}

void CameraHidlTest::setupPreviewWindow(
        const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
        sp<BufferItemConsumer> *bufferItemConsumer /*out*/,
        sp<BufferItemHander> *bufferHandler /*out*/) {
    ASSERT_NE(nullptr, device.get());
    ASSERT_NE(nullptr, bufferItemConsumer);
    ASSERT_NE(nullptr, bufferHandler);

    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferConsumer> consumer;
    BufferQueue::createBufferQueue(&producer, &consumer);
    *bufferItemConsumer = new BufferItemConsumer(consumer,
            GraphicBuffer::USAGE_HW_TEXTURE); //Use GLConsumer default usage flags
    ASSERT_NE(nullptr, (*bufferItemConsumer).get());
    *bufferHandler = new BufferItemHander(*bufferItemConsumer);
    ASSERT_NE(nullptr, (*bufferHandler).get());
    (*bufferItemConsumer)->setFrameAvailableListener(*bufferHandler);
    sp<Surface> surface = new Surface(producer);
    sp<PreviewWindowCb> previewCb = new PreviewWindowCb(surface);

    auto rc = device->setPreviewWindow(previewCb);
    ASSERT_TRUE(rc.isOk());
    ASSERT_EQ(Status::OK, rc);
}

int main(int argc, char **argv) {
  ::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance());
  ::testing::InitGoogleTest(&argc, argv);