| /* |
| * 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/device/2.1/ICameraDeviceUser.h> |
| #include <android/frameworks/cameraservice/service/2.0/ICameraService.h> |
| #include <android/frameworks/cameraservice/service/2.1/ICameraService.h> |
| #include <system/camera_metadata.h> |
| #include <system/graphics.h> |
| |
| #include <fmq/MessageQueue.h> |
| #include <utils/Condition.h> |
| #include <utils/Mutex.h> |
| #include <utils/StrongPointer.h> |
| |
| #include <gtest/gtest.h> |
| #include <hidl/GtestPrinter.h> |
| #include <hidl/ServiceManagement.h> |
| #include <stdint.h> |
| #include <unistd.h> |
| |
| #include <stdio.h> |
| #include <algorithm> |
| #include <mutex> |
| #include <string> |
| #include <unordered_set> |
| #include <vector> |
| |
| #include <media/NdkImageReader.h> |
| |
| #include <android/log.h> |
| |
| #include <CameraMetadata.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::frameworks::cameraservice::service::V2_1::PhysicalCameraStatusAndId; |
| using android::hardware::hidl_string; |
| using android::hardware::hidl_vec; |
| using android::hardware::Return; |
| using android::hardware::Void; |
| using android::hardware::camera::common::V1_0::helper::CameraMetadata; |
| using camera_metadata_enum_android_depth_available_depth_stream_configurations:: |
| ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT; |
| using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>; |
| |
| static constexpr int kCaptureRequestCount = 10; |
| static constexpr int kVGAImageWidth = 640; |
| static constexpr int kVGAImageHeight = 480; |
| 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(); |
| }; |
| }; |
| |
| class CameraServiceListener2_1 |
| : public android::frameworks::cameraservice::service::V2_1::ICameraServiceListener { |
| std::map<hidl_string, CameraDeviceStatus> mCameraStatuses; |
| std::map<hidl_string, std::set<hidl_string>> mUnavailablePhysicalCameras; |
| mutable Mutex mLock; |
| |
| public: |
| virtual ~CameraServiceListener2_1(){}; |
| |
| virtual Return<void> onStatusChanged(const CameraStatusAndId& statusAndId) override { |
| Mutex::Autolock l(mLock); |
| mCameraStatuses[statusAndId.cameraId] = statusAndId.deviceStatus; |
| return Void(); |
| }; |
| |
| virtual Return<void> onPhysicalCameraStatusChanged( |
| const PhysicalCameraStatusAndId& statusAndId) override { |
| Mutex::Autolock l(mLock); |
| ALOGI("%s: Physical camera %s : %s status changed to %d", __FUNCTION__, |
| statusAndId.cameraId.c_str(), statusAndId.physicalCameraId.c_str(), |
| statusAndId.deviceStatus); |
| |
| EXPECT_NE(mCameraStatuses.find(statusAndId.cameraId), mCameraStatuses.end()); |
| EXPECT_EQ(mCameraStatuses[statusAndId.cameraId], CameraDeviceStatus::STATUS_PRESENT); |
| |
| if (statusAndId.deviceStatus == CameraDeviceStatus::STATUS_NOT_PRESENT) { |
| auto res = mUnavailablePhysicalCameras[statusAndId.cameraId].emplace( |
| statusAndId.physicalCameraId); |
| EXPECT_TRUE(res.second); |
| } else { |
| auto res = mUnavailablePhysicalCameras[statusAndId.cameraId].erase( |
| statusAndId.physicalCameraId); |
| EXPECT_EQ(res, 1); |
| } |
| return Void(); |
| }; |
| |
| void initializeStatuses( |
| const hidl_vec<android::frameworks::cameraservice::service::V2_1::CameraStatusAndId>& |
| statuses) { |
| Mutex::Autolock l(mLock); |
| |
| for (auto& status : statuses) { |
| mCameraStatuses[status.v2_0.cameraId] = status.v2_0.deviceStatus; |
| for (auto& physicalId : status.unavailPhysicalCameraIds) { |
| mUnavailablePhysicalCameras[status.v2_0.cameraId].emplace(physicalId); |
| } |
| } |
| } |
| }; |
| |
| // 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); } |
| }; |
| |
| static bool convertFromHidlCloned(const hidl_vec<uint8_t>& metadata, CameraMetadata* rawMetadata) { |
| const camera_metadata* buffer = (camera_metadata_t*)(metadata.data()); |
| size_t expectedSize = metadata.size(); |
| int ret = validate_camera_metadata_structure(buffer, &expectedSize); |
| if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) { |
| *rawMetadata = buffer; |
| } else { |
| ALOGE("%s: Malformed camera metadata received from caller", __FUNCTION__); |
| return false; |
| } |
| return true; |
| } |
| |
| struct StreamConfiguration { |
| int32_t width = -1; |
| int32_t height = -1; |
| }; |
| |
| class VtsHalCameraServiceV2_0TargetTest : public ::testing::TestWithParam<std::string> { |
| public: |
| void SetUp() override { |
| cs = ICameraService::getService(GetParam()); |
| |
| auto castResult = |
| android::frameworks::cameraservice::service::V2_1::ICameraService::castFrom(cs); |
| if (castResult.isOk()) { |
| cs2_1 = castResult; |
| } |
| } |
| |
| 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); |
| } |
| |
| bool doesCapabilityExist(const CameraMetadata& characteristics, int capability) { |
| camera_metadata_ro_entry rawEntry = |
| characteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); |
| EXPECT_TRUE(rawEntry.count > 0); |
| for (size_t i = 0; i < rawEntry.count; i++) { |
| if (rawEntry.data.u8[i] == capability) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool isSecureOnlyDevice(const CameraMetadata& characteristics) { |
| camera_metadata_ro_entry rawEntry = |
| characteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); |
| EXPECT_TRUE(rawEntry.count > 0); |
| if (rawEntry.count == 1 && |
| rawEntry.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA) { |
| return true; |
| } |
| return false; |
| } |
| |
| // Return the first advertised available stream sizes for the given format |
| // and use-case. |
| StreamConfiguration getStreamConfiguration(const CameraMetadata& characteristics, uint32_t tag, |
| int32_t chosenUse, int32_t chosenFormat) { |
| camera_metadata_ro_entry rawEntry = characteristics.find(tag); |
| StreamConfiguration streamConfig; |
| const size_t STREAM_FORMAT_OFFSET = 0; |
| const size_t STREAM_WIDTH_OFFSET = 1; |
| const size_t STREAM_HEIGHT_OFFSET = 2; |
| const size_t STREAM_INOUT_OFFSET = 3; |
| const size_t STREAM_CONFIG_SIZE = 4; |
| if (rawEntry.count < STREAM_CONFIG_SIZE) { |
| return streamConfig; |
| } |
| EXPECT_TRUE((rawEntry.count % STREAM_CONFIG_SIZE) == 0); |
| for (size_t i = 0; i < rawEntry.count; i += STREAM_CONFIG_SIZE) { |
| int32_t format = rawEntry.data.i32[i + STREAM_FORMAT_OFFSET]; |
| int32_t use = rawEntry.data.i32[i + STREAM_INOUT_OFFSET]; |
| if (format == chosenFormat && use == chosenUse) { |
| streamConfig.width = rawEntry.data.i32[i + STREAM_WIDTH_OFFSET]; |
| streamConfig.height = rawEntry.data.i32[i + STREAM_HEIGHT_OFFSET]; |
| return streamConfig; |
| } |
| } |
| return streamConfig; |
| } |
| |
| sp<ICameraService> cs = nullptr; |
| sp<android::frameworks::cameraservice::service::V2_1::ICameraService> cs2_1 = nullptr; |
| }; |
| |
| // Basic HIDL calls for ICameraService |
| TEST_P(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) { |
| CameraMetadata rawMetadata; |
| if (it.deviceStatus != CameraDeviceStatus::STATUS_PRESENT) { |
| continue; |
| } |
| remoteRet = cs->getCameraCharacteristics( |
| it.cameraId, [&status, &rawMetadata](auto s, const hidl_vec<uint8_t>& metadata) { |
| status = s; |
| bool cStatus = convertFromHidlCloned(metadata, &rawMetadata); |
| EXPECT_TRUE(cStatus); |
| }); |
| EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR); |
| EXPECT_FALSE(rawMetadata.isEmpty()); |
| 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; |
| bool isDepthOnlyDevice = |
| !doesCapabilityExist(rawMetadata, |
| ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) && |
| doesCapabilityExist(rawMetadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT); |
| int chosenImageFormat = AIMAGE_FORMAT_YUV_420_888; |
| int chosenImageWidth = kVGAImageWidth; |
| int chosenImageHeight = kVGAImageHeight; |
| bool isSecureOnlyCamera = isSecureOnlyDevice(rawMetadata); |
| status_t mStatus = OK; |
| if (isSecureOnlyCamera) { |
| StreamConfiguration secureStreamConfig = |
| getStreamConfiguration(rawMetadata, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, |
| ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, |
| HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED); |
| EXPECT_TRUE(secureStreamConfig.width != -1); |
| EXPECT_TRUE(secureStreamConfig.height != -1); |
| chosenImageFormat = AIMAGE_FORMAT_PRIVATE; |
| chosenImageWidth = secureStreamConfig.width; |
| chosenImageHeight = secureStreamConfig.height; |
| mStatus = AImageReader_newWithUsage( |
| chosenImageWidth, chosenImageHeight, chosenImageFormat, |
| AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT, kCaptureRequestCount, &reader); |
| |
| } else { |
| if (isDepthOnlyDevice) { |
| StreamConfiguration depthStreamConfig = getStreamConfiguration( |
| rawMetadata, ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, |
| ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT, |
| HAL_PIXEL_FORMAT_Y16); |
| EXPECT_TRUE(depthStreamConfig.width != -1); |
| EXPECT_TRUE(depthStreamConfig.height != -1); |
| chosenImageFormat = AIMAGE_FORMAT_DEPTH16; |
| chosenImageWidth = depthStreamConfig.width; |
| chosenImageHeight = depthStreamConfig.height; |
| } |
| mStatus = AImageReader_new(chosenImageWidth, chosenImageHeight, chosenImageFormat, |
| 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); |
| |
| /** |
| * For camera device V2.1, test newly added functions. |
| * TODO: Refactor the device 2.1 test into a separate test for service 2.2. |
| */ |
| auto castResult = |
| android::frameworks::cameraservice::device::V2_1::ICameraDeviceUser::castFrom( |
| deviceRemote); |
| sp<android::frameworks::cameraservice::device::V2_1::ICameraDeviceUser> deviceRemote2_1; |
| if (castResult.isOk()) { |
| deviceRemote2_1 = castResult; |
| } |
| if (deviceRemote2_1 != nullptr) { |
| // Reconfigure a capture session using v2.1 version of the device |
| ret = deviceRemote2_1->beginConfigure(); |
| EXPECT_TRUE(ret.isOk() && ret == Status::NO_ERROR); |
| remoteRet = |
| deviceRemote2_1->createStream(output, [&status, &streamId](Status s, auto sId) { |
| status = s; |
| streamId = sId; |
| }); |
| EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR); |
| EXPECT_TRUE(streamId >= 0); |
| ret = deviceRemote2_1->endConfigure_2_1(StreamConfigurationMode::NORMAL_MODE, |
| hidlParams, systemTime()); |
| EXPECT_TRUE(ret.isOk() && ret == Status::NO_ERROR); |
| } |
| |
| remoteRet = deviceRemote->disconnect(); |
| EXPECT_TRUE(remoteRet.isOk()); |
| } |
| Return<Status> ret = cs->removeListener(listener); |
| EXPECT_TRUE(ret.isOk() && ret == Status::NO_ERROR); |
| } |
| |
| TEST_P(VtsHalCameraServiceV2_0TargetTest, CameraServiceListener2_1Test) { |
| sp<CameraServiceListener2_1> listener2_1(new CameraServiceListener2_1()); |
| hidl_vec<android::frameworks::cameraservice::service::V2_1::CameraStatusAndId> |
| cameraStatuses2_1{}; |
| Status status = Status::NO_ERROR; |
| |
| if (cs2_1 == nullptr) return; |
| |
| auto remoteRet = cs2_1->addListener_2_1( |
| listener2_1, [&status, &cameraStatuses2_1](Status s, auto& retStatuses) { |
| status = s; |
| cameraStatuses2_1 = retStatuses; |
| }); |
| EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR); |
| listener2_1->initializeStatuses(cameraStatuses2_1); |
| |
| for (const auto& it : cameraStatuses2_1) { |
| CameraMetadata rawMetadata; |
| remoteRet = cs2_1->getCameraCharacteristics( |
| it.v2_0.cameraId, [&status, &rawMetadata](auto s, const hidl_vec<uint8_t>& metadata) { |
| status = s; |
| bool cStatus = convertFromHidlCloned(metadata, &rawMetadata); |
| EXPECT_TRUE(cStatus); |
| }); |
| EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR); |
| EXPECT_FALSE(rawMetadata.isEmpty()); |
| bool isLogicalCamera = doesCapabilityExist( |
| rawMetadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA); |
| if (!isLogicalCamera) { |
| EXPECT_TRUE(it.unavailPhysicalCameraIds.size() == 0); |
| continue; |
| } |
| camera_metadata_entry entry = rawMetadata.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS); |
| EXPECT_GT(entry.count, 0); |
| |
| std::unordered_set<std::string> validPhysicalIds; |
| const uint8_t* ids = entry.data.u8; |
| size_t start = 0; |
| for (size_t i = 0; i < entry.count; i++) { |
| if (ids[i] == '\0') { |
| if (start != i) { |
| std::string currentId(reinterpret_cast<const char*>(ids + start)); |
| validPhysicalIds.emplace(currentId); |
| } |
| start = i + 1; |
| } |
| } |
| |
| std::unordered_set<std::string> unavailablePhysicalIds(it.unavailPhysicalCameraIds.begin(), |
| it.unavailPhysicalCameraIds.end()); |
| EXPECT_EQ(unavailablePhysicalIds.size(), it.unavailPhysicalCameraIds.size()); |
| for (auto& unavailablePhysicalId : unavailablePhysicalIds) { |
| EXPECT_NE(validPhysicalIds.find(unavailablePhysicalId), validPhysicalIds.end()); |
| } |
| } |
| |
| auto remoteStatus = cs2_1->removeListener(listener2_1); |
| EXPECT_TRUE(remoteStatus.isOk() && remoteStatus == Status::NO_ERROR); |
| } |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VtsHalCameraServiceV2_0TargetTest); |
| INSTANTIATE_TEST_SUITE_P( |
| PerInstance, VtsHalCameraServiceV2_0TargetTest, |
| testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraService::descriptor)), |
| android::hardware::PrintInstanceNameToString); |
| } // namespace android |