C++程序  |  395行  |  15.25 KB

/*
 * Copyright (C) 2019 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 "VtsHalCameraServiceV2_0TargetTest"
//#define LOG_NDEBUG 0

#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceUser.h>
#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>

#include <fmq/MessageQueue.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/StrongPointer.h>

#include <gtest/gtest.h>
#include <stdint.h>
#include <unistd.h>

#include <stdio.h>
#include <algorithm>
#include <mutex>
#include <string>
#include <vector>

#include <media/NdkImageReader.h>

#include <android/log.h>

#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>

namespace android {

using android::Condition;
using android::Mutex;
using android::sp;
using android::frameworks::cameraservice::common::V2_0::Status;
using android::frameworks::cameraservice::device::V2_0::CaptureRequest;
using android::frameworks::cameraservice::device::V2_0::CaptureResultExtras;
using android::frameworks::cameraservice::device::V2_0::ErrorCode;
using android::frameworks::cameraservice::device::V2_0::FmqSizeOrMetadata;
using android::frameworks::cameraservice::device::V2_0::ICameraDeviceCallback;
using android::frameworks::cameraservice::device::V2_0::ICameraDeviceUser;
using android::frameworks::cameraservice::device::V2_0::OutputConfiguration;
using android::frameworks::cameraservice::device::V2_0::PhysicalCaptureResultInfo;
using android::frameworks::cameraservice::device::V2_0::StreamConfigurationMode;
using android::frameworks::cameraservice::device::V2_0::SubmitInfo;
using android::frameworks::cameraservice::device::V2_0::TemplateId;
using android::frameworks::cameraservice::service::V2_0::CameraDeviceStatus;
using android::frameworks::cameraservice::service::V2_0::CameraStatusAndId;
using android::frameworks::cameraservice::service::V2_0::ICameraService;
using android::frameworks::cameraservice::service::V2_0::ICameraServiceListener;
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::hardware::Void;
using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;

static constexpr int kCaptureRequestCount = 10;
static constexpr int kImageWidth = 640;
static constexpr int kImageHeight = 480;
static constexpr int kImageFormat = AIMAGE_FORMAT_YUV_420_888;
static constexpr int kNumRequests = 4;

#define ASSERT_NOT_NULL(x) ASSERT_TRUE((x) != nullptr)

#define SETUP_TIMEOUT 2000000000  // ns
#define IDLE_TIMEOUT 2000000000   // ns

// Stub listener implementation
class CameraServiceListener : public ICameraServiceListener {
    std::map<hidl_string, CameraDeviceStatus> mCameraStatuses;
    mutable Mutex mLock;

   public:
    virtual ~CameraServiceListener(){};

    virtual Return<void> onStatusChanged(const CameraStatusAndId& statusAndId) override {
        Mutex::Autolock l(mLock);
        mCameraStatuses[statusAndId.cameraId] = statusAndId.deviceStatus;
        return Void();
    };
};

// ICameraDeviceCallback implementation
class CameraDeviceCallbacks : public ICameraDeviceCallback {
   public:
    enum Status {
        IDLE,
        ERROR,
        PREPARED,
        RUNNING,
        RESULT_RECEIVED,
        UNINITIALIZED,
        REPEATING_REQUEST_ERROR,
    };

   protected:
    bool mError = false;
    Status mLastStatus = UNINITIALIZED;
    mutable std::vector<Status> mStatusesHit;
    mutable Mutex mLock;
    mutable Condition mStatusCondition;

   public:
    CameraDeviceCallbacks() {}

    virtual ~CameraDeviceCallbacks() {}

    virtual Return<void> onDeviceError(ErrorCode errorCode,
                                       const CaptureResultExtras& resultExtras) override {
        (void)resultExtras;
        ALOGE("%s: onDeviceError occurred with: %d", __FUNCTION__, static_cast<int>(errorCode));
        Mutex::Autolock l(mLock);
        mError = true;
        mLastStatus = ERROR;
        mStatusesHit.push_back(mLastStatus);
        mStatusCondition.broadcast();
        return Void();
    }

    virtual Return<void> onDeviceIdle() override {
        Mutex::Autolock l(mLock);
        mLastStatus = IDLE;
        mStatusesHit.push_back(mLastStatus);
        mStatusCondition.broadcast();
        return Void();
    }

    virtual Return<void> onCaptureStarted(const CaptureResultExtras& resultExtras,
                                          uint64_t timestamp) override {
        (void)resultExtras;
        (void)timestamp;
        Mutex::Autolock l(mLock);
        mLastStatus = RUNNING;
        mStatusesHit.push_back(mLastStatus);
        mStatusCondition.broadcast();
        return Void();
    }

    virtual Return<void> onResultReceived(
        const FmqSizeOrMetadata& sizeOrMetadata, const CaptureResultExtras& resultExtras,
        const hidl_vec<PhysicalCaptureResultInfo>& physicalResultInfos) override {
        (void)sizeOrMetadata;
        (void)resultExtras;
        (void)physicalResultInfos;
        Mutex::Autolock l(mLock);
        mLastStatus = RESULT_RECEIVED;
        mStatusesHit.push_back(mLastStatus);
        mStatusCondition.broadcast();
        return Void();
    }

    virtual Return<void> onRepeatingRequestError(uint64_t lastFrameNumber,
                                                 int32_t stoppedSequenceId) override {
        (void)lastFrameNumber;
        (void)stoppedSequenceId;
        Mutex::Autolock l(mLock);
        mLastStatus = REPEATING_REQUEST_ERROR;
        mStatusesHit.push_back(mLastStatus);
        mStatusCondition.broadcast();
        return Void();
    }

    // Test helper functions:

    bool hadError() const {
        Mutex::Autolock l(mLock);
        return mError;
    }
    bool waitForStatus(Status status) const {
        Mutex::Autolock l(mLock);
        if (mLastStatus == status) {
            return true;
        }

        while (std::find(mStatusesHit.begin(), mStatusesHit.end(), status) == mStatusesHit.end()) {
            if (mStatusCondition.waitRelative(mLock, IDLE_TIMEOUT) != android::OK) {
                mStatusesHit.clear();
                return false;
            }
        }
        mStatusesHit.clear();

        return true;
    }

    void clearStatus() const {
        Mutex::Autolock l(mLock);
        mStatusesHit.clear();
    }

    bool waitForIdle() const { return waitForStatus(IDLE); }
};

class CameraHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
   public:
    // get the test environment singleton
    static CameraHidlEnvironment* Instance() {
        static CameraHidlEnvironment* instance = new CameraHidlEnvironment();
        return instance;
    }

    virtual void registerTestServices() override { registerTestService<ICameraService>(); }
};

class VtsHalCameraServiceV2_0TargetTest : public ::testing::Test {
   public:
    void SetUp() override {
        cs = ::testing::VtsHalHidlTargetTestBase::getService<ICameraService>(
            CameraHidlEnvironment::Instance()->getServiceName<ICameraService>());
    }
    void TearDown() override {}
    // creates an outputConfiguration with no deferred streams
    OutputConfiguration createOutputConfiguration(const std::vector<native_handle_t*>& nhs) {
        OutputConfiguration output;
        output.rotation = OutputConfiguration::Rotation::R0;
        output.windowGroupId = -1;
        output.windowHandles.resize(nhs.size());
        output.width = 0;
        output.height = 0;
        output.isDeferred = false;
        for (size_t i = 0; i < nhs.size(); i++) {
            output.windowHandles[i] = nhs[i];
        }
        return output;
    }

    void initializeCaptureRequestPartial(CaptureRequest* captureRequest, int32_t streamId,
                                         const hidl_string& cameraId, size_t settingsSize) {
        captureRequest->physicalCameraSettings.resize(1);
        captureRequest->physicalCameraSettings[0].id = cameraId;
        captureRequest->streamAndWindowIds.resize(1);
        captureRequest->streamAndWindowIds[0].streamId = streamId;
        captureRequest->streamAndWindowIds[0].windowId = 0;
        // Write the settings metadata into the fmq.
        captureRequest->physicalCameraSettings[0].settings.fmqMetadataSize(settingsSize);
    }

    sp<ICameraService> cs = nullptr;
};

// Basic HIDL calls for ICameraService
TEST_F(VtsHalCameraServiceV2_0TargetTest, BasicCameraLifeCycleTest) {
    sp<CameraServiceListener> listener(new CameraServiceListener());
    hidl_vec<CameraStatusAndId> cameraStatuses{};
    Status status = Status::NO_ERROR;
    auto remoteRet =
        cs->addListener(listener, [&status, &cameraStatuses](Status s, auto& retStatuses) {
            status = s;
            cameraStatuses = retStatuses;
        });
    EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR);
    for (const auto& it : cameraStatuses) {
        hidl_vec<uint8_t> rawMetadata;
        listener->onStatusChanged(it);
        if (it.deviceStatus != CameraDeviceStatus::STATUS_PRESENT) {
            continue;
        }
        remoteRet = cs->getCameraCharacteristics(
            it.cameraId, [&status, &rawMetadata](auto s, const hidl_vec<uint8_t>& metadata) {
                status = s;
                rawMetadata = metadata;
            });
        EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR);
        EXPECT_TRUE(rawMetadata.size() != 0);
        sp<CameraDeviceCallbacks> callbacks(new CameraDeviceCallbacks());
        sp<ICameraDeviceUser> deviceRemote = nullptr;
        remoteRet = cs->connectDevice(callbacks, it.cameraId,
                                      [&status, &deviceRemote](auto s, auto& device) {
                                          status = s;
                                          deviceRemote = device;
                                      });
        EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR);
        EXPECT_TRUE(deviceRemote != nullptr);

        std::shared_ptr<RequestMetadataQueue> requestMQ = nullptr;
        remoteRet = deviceRemote->getCaptureRequestMetadataQueue([&requestMQ](const auto& mqD) {
            requestMQ = std::make_shared<RequestMetadataQueue>(mqD);
            EXPECT_TRUE(requestMQ->isValid() && (requestMQ->availableToWrite() >= 0));
        });
        EXPECT_TRUE(remoteRet.isOk());
        AImageReader* reader = nullptr;
        auto mStatus = AImageReader_new(kImageWidth, kImageHeight, kImageFormat,
                                        kCaptureRequestCount, &reader);
        EXPECT_EQ(mStatus, AMEDIA_OK);
        native_handle_t* wh = nullptr;
        mStatus = AImageReader_getWindowNativeHandle(reader, &wh);
        EXPECT_TRUE(mStatus == AMEDIA_OK && wh != nullptr);
        OutputConfiguration output = createOutputConfiguration({wh});
        Return<Status> ret = deviceRemote->beginConfigure();
        EXPECT_TRUE(ret.isOk() && ret == Status::NO_ERROR);
        int32_t streamId = -1;
        remoteRet = deviceRemote->createStream(output, [&status, &streamId](Status s, auto sId) {
            status = s;
            streamId = sId;
        });
        EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR);
        EXPECT_TRUE(streamId >= 0);
        hidl_vec<uint8_t> hidlParams;
        ret = deviceRemote->endConfigure(StreamConfigurationMode::NORMAL_MODE, hidlParams);
        EXPECT_TRUE(ret.isOk() && ret == Status::NO_ERROR);
        hidl_vec<uint8_t> settingsMetadata;
        remoteRet = deviceRemote->createDefaultRequest(
            TemplateId::PREVIEW, [&status, &settingsMetadata](auto s, const hidl_vec<uint8_t> m) {
                status = s;
                settingsMetadata = m;
            });
        EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR);
        EXPECT_GE(settingsMetadata.size(), 0);
        hidl_vec<CaptureRequest> captureRequests;
        captureRequests.resize(kNumRequests);
        for (int i = 0; i < kNumRequests; i++) {
            CaptureRequest& captureRequest = captureRequests[i];
            initializeCaptureRequestPartial(&captureRequest, streamId, it.cameraId,
                                            settingsMetadata.size());
            // Write the settings metadata into the fmq.
            bool written = requestMQ->write(settingsMetadata.data(), settingsMetadata.size());
            EXPECT_TRUE(written);
        }
        SubmitInfo info;

        // Test a single capture
        remoteRet = deviceRemote->submitRequestList(captureRequests, false,
                                                    [&status, &info](auto s, auto& submitInfo) {
                                                        status = s;
                                                        info = submitInfo;
                                                    });
        EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR);
        EXPECT_GE(info.requestId, 0);
        EXPECT_TRUE(callbacks->waitForStatus(CameraDeviceCallbacks::Status::RESULT_RECEIVED));
        EXPECT_TRUE(callbacks->waitForIdle());

        // Test repeating requests
        CaptureRequest captureRequest;

        initializeCaptureRequestPartial(&captureRequest, streamId, it.cameraId,
                                        settingsMetadata.size());

        bool written = requestMQ->write(settingsMetadata.data(), settingsMetadata.size());
        EXPECT_TRUE(written);

        remoteRet = deviceRemote->submitRequestList({captureRequest}, true,
                                                    [&status, &info](auto s, auto& submitInfo) {
                                                        status = s;
                                                        info = submitInfo;
                                                    });
        EXPECT_TRUE(callbacks->waitForStatus(CameraDeviceCallbacks::Status::RESULT_RECEIVED));
        int64_t lastFrameNumber = -1;
        remoteRet =
            deviceRemote->cancelRepeatingRequest([&status, &lastFrameNumber](auto s, int64_t lf) {
                status = s;
                lastFrameNumber = lf;
            });
        EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR);
        EXPECT_GE(lastFrameNumber, 0);

        // Test waitUntilIdle()
        auto statusRet = deviceRemote->waitUntilIdle();
        EXPECT_TRUE(statusRet.isOk() && statusRet == Status::NO_ERROR);

        // Test deleteStream()
        statusRet = deviceRemote->deleteStream(streamId);
        EXPECT_TRUE(statusRet.isOk() && statusRet == Status::NO_ERROR);

        remoteRet = deviceRemote->disconnect();
        EXPECT_TRUE(remoteRet.isOk());
    }
    Return<Status> ret = cs->removeListener(listener);
    EXPECT_TRUE(ret.isOk() && ret == Status::NO_ERROR);
}

}  // namespace android

int main(int argc, char** argv) {
    ::testing::AddGlobalTestEnvironment(android::CameraHidlEnvironment::Instance());
    ::testing::InitGoogleTest(&argc, argv);
    android::CameraHidlEnvironment::Instance()->init(&argc, argv);
    int status = RUN_ALL_TESTS();
    return status;
}