HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Pie
|
9.0.0_r8
下载
查看原文件
收藏
根目录
hardware
interfaces
camera
provider
2.4
vts
functional
VtsHalCameraProviderV2_4TargetTest.cpp
/* * Copyright (C) 2016-2018 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 "camera_hidl_hal_test" #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace ::android::hardware::camera::device; using ::android::hardware::Return; using ::android::hardware::Void; 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::BufferItemConsumer; using ::android::Surface; using ::android::hardware::graphics::common::V1_0::BufferUsage; using ::android::hardware::graphics::common::V1_0::Dataspace; using ::android::hardware::graphics::common::V1_0::PixelFormat; using ::android::hardware::camera::common::V1_0::Status; using ::android::hardware::camera::common::V1_0::CameraDeviceStatus; using ::android::hardware::camera::common::V1_0::TorchMode; using ::android::hardware::camera::common::V1_0::TorchModeStatus; using ::android::hardware::camera::common::V1_0::helper::CameraParameters; using ::android::hardware::camera::common::V1_0::helper::Size; using ::android::hardware::camera::provider::V2_4::ICameraProvider; using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback; using ::android::hardware::camera::device::V3_2::ICameraDevice; using ::android::hardware::camera::device::V3_2::BufferCache; using ::android::hardware::camera::device::V3_2::CaptureRequest; using ::android::hardware::camera::device::V3_2::CaptureResult; using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback; using ::android::hardware::camera::device::V3_2::ICameraDeviceSession; using ::android::hardware::camera::device::V3_2::NotifyMsg; using ::android::hardware::camera::device::V3_2::RequestTemplate; using ::android::hardware::camera::device::V3_2::StreamType; using ::android::hardware::camera::device::V3_2::StreamRotation; using ::android::hardware::camera::device::V3_2::StreamConfiguration; using ::android::hardware::camera::device::V3_2::StreamConfigurationMode; using ::android::hardware::camera::device::V3_2::CameraMetadata; using ::android::hardware::camera::device::V3_2::HalStreamConfiguration; using ::android::hardware::camera::device::V3_2::BufferStatus; using ::android::hardware::camera::device::V3_2::StreamBuffer; using ::android::hardware::camera::device::V3_2::MsgType; using ::android::hardware::camera::device::V3_2::ErrorMsg; using ::android::hardware::camera::device::V3_2::ErrorCode; using ::android::hardware::camera::device::V1_0::CameraFacing; using ::android::hardware::camera::device::V1_0::NotifyCallbackMsg; using ::android::hardware::camera::device::V1_0::CommandType; using ::android::hardware::camera::device::V1_0::DataCallbackMsg; using ::android::hardware::camera::device::V1_0::CameraFrameMetadata; using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback; using ::android::hardware::camera::device::V1_0::FrameCallbackFlag; using ::android::hardware::camera::device::V1_0::HandleTimestampMessage; using ::android::hardware::MessageQueue; using ::android::hardware::kSynchronizedReadWrite; using ::android::hidl::allocator::V1_0::IAllocator; using ::android::hidl::memory::V1_0::IMemory; using ::android::hidl::memory::V1_0::IMapper; using ResultMetadataQueue = MessageQueue
; using ::android::hidl::manager::V1_0::IServiceManager; using namespace ::android::hardware::camera; const uint32_t kMaxPreviewWidth = 1920; const uint32_t kMaxPreviewHeight = 1080; const uint32_t kMaxVideoWidth = 4096; const uint32_t kMaxVideoHeight = 2160; const int64_t kStreamBufferTimeoutSec = 3; const int64_t kAutoFocusTimeoutSec = 5; const int64_t kTorchTimeoutSec = 1; const int64_t kEmptyFlushTimeoutMSec = 200; const char kDumpOutput[] = "/dev/null"; const uint32_t kBurstFrameCount = 10; struct AvailableStream { int32_t width; int32_t height; int32_t format; }; struct AvailableZSLInputOutput { int32_t inputFormat; int32_t outputFormat; }; namespace { // "device@
/legacy/
" const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)"; const int CAMERA_DEVICE_API_VERSION_3_4 = 0x304; const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303; const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302; const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100; const char *kHAL3_4 = "3.4"; const char *kHAL3_3 = "3.3"; const char *kHAL3_2 = "3.2"; const char *kHAL1_0 = "1.0"; bool matchDeviceName(const hidl_string& deviceName, const hidl_string &providerType, std::string* deviceVersion, std::string* cameraId) { ::android::String8 pattern; pattern.appendFormat(kDeviceNameRE, providerType.c_str()); std::regex e(pattern.string()); std::string deviceNameStd(deviceName.c_str()); std::smatch sm; if (std::regex_match(deviceNameStd, sm, e)) { if (deviceVersion != nullptr) { *deviceVersion = sm[1]; } if (cameraId != nullptr) { *cameraId = sm[2]; } return true; } return false; } int getCameraDeviceVersion(const hidl_string& deviceName, const hidl_string &providerType) { std::string version; bool match = matchDeviceName(deviceName, providerType, &version, nullptr); if (!match) { return -1; } if (version.compare(kHAL3_4) == 0) { return CAMERA_DEVICE_API_VERSION_3_4; } else if (version.compare(kHAL3_3) == 0) { return CAMERA_DEVICE_API_VERSION_3_3; } else if (version.compare(kHAL3_2) == 0) { return CAMERA_DEVICE_API_VERSION_3_2; } else if (version.compare(kHAL1_0) == 0) { return CAMERA_DEVICE_API_VERSION_1_0; } return 0; } bool parseProviderName(const std::string& name, std::string *type /*out*/, uint32_t *id /*out*/) { if (!type || !id) { ADD_FAILURE(); return false; } std::string::size_type slashIdx = name.find('/'); if (slashIdx == std::string::npos || slashIdx == name.size() - 1) { ADD_FAILURE() << "Provider name does not have / separator between type" "and id"; return false; } std::string typeVal = name.substr(0, slashIdx); char *endPtr; errno = 0; long idVal = strtol(name.c_str() + slashIdx + 1, &endPtr, 10); if (errno != 0) { ADD_FAILURE() << "cannot parse provider id as an integer:" << name.c_str() << strerror(errno) << errno; return false; } if (endPtr != name.c_str() + name.size()) { ADD_FAILURE() << "provider id has unexpected length " << name.c_str(); return false; } if (idVal < 0) { ADD_FAILURE() << "id is negative: " << name.c_str() << idVal; return false; } *type = typeVal; *id = static_cast
(idVal); return true; } Status mapToStatus(::android::status_t s) { switch(s) { case ::android::OK: return Status::OK ; case ::android::BAD_VALUE: return Status::ILLEGAL_ARGUMENT ; case -EBUSY: return Status::CAMERA_IN_USE; case -EUSERS: return Status::MAX_CAMERAS_IN_USE; case ::android::UNKNOWN_TRANSACTION: return Status::METHOD_NOT_SUPPORTED; case ::android::INVALID_OPERATION: return Status::OPERATION_NOT_SUPPORTED; case ::android::DEAD_OBJECT: return Status::CAMERA_DISCONNECTED; } ALOGW("Unexpected HAL status code %d", s); return Status::OPERATION_NOT_SUPPORTED; } } // Test environment for camera class CameraHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: // get the test environment singleton static CameraHidlEnvironment* Instance() { static CameraHidlEnvironment* instance = new CameraHidlEnvironment; return instance; } virtual void HidlSetUp() override { ALOGI("SetUp CameraHidlEnvironment"); } virtual void HidlTearDown() override { ALOGI("TearDown CameraHidlEnvironment"); } virtual void registerTestServices() override { registerTestService
(); } private: CameraHidlEnvironment() {} GTEST_DISALLOW_COPY_AND_ASSIGN_(CameraHidlEnvironment); }; struct BufferItemHander: public BufferItemConsumer::FrameAvailableListener { BufferItemHander(wp
consumer) : mConsumer(consumer) {} void onFrameAvailable(const android::BufferItem&) override { sp
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
mConsumer; }; struct PreviewWindowCb : public ICameraDevicePreviewCallback { PreviewWindowCb(sp
anw) : mPreviewWidth(0), mPreviewHeight(0), mFormat(0), mPreviewUsage(0), mPreviewSwapInterval(-1), mCrop{-1, -1, -1, -1}, mAnw(anw) {} using dequeueBuffer_cb = std::function
; Return
dequeueBuffer(dequeueBuffer_cb _hidl_cb) override; Return
enqueueBuffer(uint64_t bufferId) override; Return
cancelBuffer(uint64_t bufferId) override; Return
setBufferCount(uint32_t count) override; Return
setBuffersGeometry(uint32_t w, uint32_t h, PixelFormat format) override; Return
setCrop(int32_t left, int32_t top, int32_t right, int32_t bottom) override; Return
setUsage(BufferUsage usage) override; Return
setSwapInterval(int32_t interval) override; using getMinUndequeuedBufferCount_cb = std::function
; Return
getMinUndequeuedBufferCount( getMinUndequeuedBufferCount_cb _hidl_cb) override; Return
setTimestamp(int64_t timestamp) override; private: struct BufferHasher { size_t operator()(const buffer_handle_t& buf) const { if (buf == nullptr) return 0; size_t result = 1; result = 31 * result + buf->numFds; for (int i = 0; i < buf->numFds; i++) { result = 31 * result + buf->data[i]; } return result; } }; struct BufferComparator { bool operator()(const buffer_handle_t& buf1, const buffer_handle_t& buf2) const { if (buf1->numFds == buf2->numFds) { for (int i = 0; i < buf1->numFds; i++) { if (buf1->data[i] != buf2->data[i]) { return false; } } return true; } return false; } }; std::pair
getBufferId(ANativeWindowBuffer* anb); void cleanupCirculatingBuffers(); std::mutex mBufferIdMapLock; // protecting mBufferIdMap and mNextBufferId typedef std::unordered_map
BufferIdMap; BufferIdMap mBufferIdMap; // stream ID -> per stream buffer ID map std::unordered_map
mReversedBufMap; uint64_t mNextBufferId = 1; uint32_t mPreviewWidth, mPreviewHeight; int mFormat, mPreviewUsage; int32_t mPreviewSwapInterval; android_native_rect_t mCrop; sp
mAnw; //Native window reference }; std::pair
PreviewWindowCb::getBufferId( ANativeWindowBuffer* anb) { std::lock_guard
lock(mBufferIdMapLock); buffer_handle_t& buf = anb->handle; auto it = mBufferIdMap.find(buf); if (it == mBufferIdMap.end()) { uint64_t bufId = mNextBufferId++; mBufferIdMap[buf] = bufId; mReversedBufMap[bufId] = anb; return std::make_pair(true, bufId); } else { return std::make_pair(false, it->second); } } void PreviewWindowCb::cleanupCirculatingBuffers() { std::lock_guard
lock(mBufferIdMapLock); mBufferIdMap.clear(); mReversedBufMap.clear(); } Return
PreviewWindowCb::dequeueBuffer(dequeueBuffer_cb _hidl_cb) { ANativeWindowBuffer* anb; auto rc = native_window_dequeue_buffer_and_wait(mAnw.get(), &anb); uint64_t bufferId = 0; uint32_t stride = 0; hidl_handle buf = nullptr; if (rc == ::android::OK) { auto pair = getBufferId(anb); buf = (pair.first) ? anb->handle : nullptr; bufferId = pair.second; stride = anb->stride; } _hidl_cb(mapToStatus(rc), bufferId, buf, stride); return Void(); } Return
PreviewWindowCb::enqueueBuffer(uint64_t bufferId) { if (mReversedBufMap.count(bufferId) == 0) { ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId); return Status::ILLEGAL_ARGUMENT; } return mapToStatus(mAnw->queueBuffer(mAnw.get(), mReversedBufMap.at(bufferId), -1)); } Return
PreviewWindowCb::cancelBuffer(uint64_t bufferId) { if (mReversedBufMap.count(bufferId) == 0) { ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId); return Status::ILLEGAL_ARGUMENT; } return mapToStatus(mAnw->cancelBuffer(mAnw.get(), mReversedBufMap.at(bufferId), -1)); } Return
PreviewWindowCb::setBufferCount(uint32_t count) { if (mAnw.get() != nullptr) { // WAR for b/27039775 native_window_api_disconnect(mAnw.get(), NATIVE_WINDOW_API_CAMERA); native_window_api_connect(mAnw.get(), NATIVE_WINDOW_API_CAMERA); if (mPreviewWidth != 0) { native_window_set_buffers_dimensions(mAnw.get(), mPreviewWidth, mPreviewHeight); native_window_set_buffers_format(mAnw.get(), mFormat); } if (mPreviewUsage != 0) { native_window_set_usage(mAnw.get(), mPreviewUsage); } if (mPreviewSwapInterval >= 0) { mAnw->setSwapInterval(mAnw.get(), mPreviewSwapInterval); } if (mCrop.left >= 0) { native_window_set_crop(mAnw.get(), &(mCrop)); } } auto rc = native_window_set_buffer_count(mAnw.get(), count); if (rc == ::android::OK) { cleanupCirculatingBuffers(); } return mapToStatus(rc); } Return
PreviewWindowCb::setBuffersGeometry(uint32_t w, uint32_t h, PixelFormat format) { auto rc = native_window_set_buffers_dimensions(mAnw.get(), w, h); if (rc == ::android::OK) { mPreviewWidth = w; mPreviewHeight = h; rc = native_window_set_buffers_format(mAnw.get(), static_cast
(format)); if (rc == ::android::OK) { mFormat = static_cast
(format); } } return mapToStatus(rc); } Return
PreviewWindowCb::setCrop(int32_t left, int32_t top, int32_t right, int32_t bottom) { android_native_rect_t crop = { left, top, right, bottom }; auto rc = native_window_set_crop(mAnw.get(), &crop); if (rc == ::android::OK) { mCrop = crop; } return mapToStatus(rc); } Return
PreviewWindowCb::setUsage(BufferUsage usage) { auto rc = native_window_set_usage(mAnw.get(), static_cast
(usage)); if (rc == ::android::OK) { mPreviewUsage = static_cast
(usage); } return mapToStatus(rc); } Return
PreviewWindowCb::setSwapInterval(int32_t interval) { auto rc = mAnw->setSwapInterval(mAnw.get(), interval); if (rc == ::android::OK) { mPreviewSwapInterval = interval; } return mapToStatus(rc); } Return
PreviewWindowCb::getMinUndequeuedBufferCount( getMinUndequeuedBufferCount_cb _hidl_cb) { int count = 0; auto rc = mAnw->query(mAnw.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &count); _hidl_cb(mapToStatus(rc), count); return Void(); } Return
PreviewWindowCb::setTimestamp(int64_t timestamp) { return mapToStatus(native_window_set_buffers_timestamp(mAnw.get(), timestamp)); } // The main test class for camera HIDL HAL. class CameraHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { string service_name = CameraHidlEnvironment::Instance()->getServiceName
(); ALOGI("get service with name: %s", service_name.c_str()); mProvider = ::testing::VtsHalHidlTargetTestBase::getService
(service_name); ASSERT_NE(mProvider, nullptr); uint32_t id; ASSERT_TRUE(parseProviderName(service_name, &mProviderType, &id)); } virtual void TearDown() override {} hidl_vec
getCameraDeviceNames(sp
provider); struct EmptyDeviceCb : public ICameraDeviceCallback { virtual Return
processCaptureResult( const hidl_vec
& /*results*/) override { ALOGI("processCaptureResult callback"); ADD_FAILURE(); // Empty callback should not reach here return Void(); } virtual Return
notify(const hidl_vec
& /*msgs*/) override { ALOGI("notify callback"); ADD_FAILURE(); // Empty callback should not reach here return Void(); } }; struct DeviceCb : public V3_4::ICameraDeviceCallback { DeviceCb(CameraHidlTest *parent) : mParent(parent) {} Return
processCaptureResult_3_4( const hidl_vec
& results) override; Return
processCaptureResult(const hidl_vec
& results) override; Return
notify(const hidl_vec
& msgs) override; private: bool processCaptureResultLocked(const CaptureResult& results); CameraHidlTest *mParent; // Parent object }; struct TorchProviderCb : public ICameraProviderCallback { TorchProviderCb(CameraHidlTest *parent) : mParent(parent) {} virtual Return
cameraDeviceStatusChange( const hidl_string&, CameraDeviceStatus) override { return Void(); } virtual Return
torchModeStatusChange( const hidl_string&, TorchModeStatus newStatus) override { std::lock_guard
l(mParent->mTorchLock); mParent->mTorchStatus = newStatus; mParent->mTorchCond.notify_one(); return Void(); } private: CameraHidlTest *mParent; // Parent object }; struct Camera1DeviceCb : public ::android::hardware::camera::device::V1_0::ICameraDeviceCallback { Camera1DeviceCb(CameraHidlTest *parent) : mParent(parent) {} Return
notifyCallback(NotifyCallbackMsg msgType, int32_t ext1, int32_t ext2) override; Return
registerMemory(const hidl_handle& descriptor, uint32_t bufferSize, uint32_t bufferCount) override; Return
unregisterMemory(uint32_t memId) override; Return
dataCallback(DataCallbackMsg msgType, uint32_t data, uint32_t bufferIndex, const CameraFrameMetadata& metadata) override; Return
dataCallbackTimestamp(DataCallbackMsg msgType, uint32_t data, uint32_t bufferIndex, int64_t timestamp) override; Return
handleCallbackTimestamp(DataCallbackMsg msgType, const hidl_handle& frameData,uint32_t data, uint32_t bufferIndex, int64_t timestamp) override; Return
handleCallbackTimestampBatch(DataCallbackMsg msgType, const ::android::hardware::hidl_vec
& batch) override; private: CameraHidlTest *mParent; // Parent object }; void openCameraDevice(const std::string &name, sp
provider, sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device /*out*/); void setupPreviewWindow( const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device, sp
*bufferItemConsumer /*out*/, sp
*bufferHandler /*out*/); void stopPreviewAndClose( const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device); void startPreview( const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device); void enableMsgType(unsigned int msgType, const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device); void disableMsgType(unsigned int msgType, const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device); void getParameters( const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device, CameraParameters *cameraParams /*out*/); void setParameters( const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device, const CameraParameters &cameraParams); void allocateGraphicBuffer(uint32_t width, uint32_t height, uint64_t usage, PixelFormat format, hidl_handle *buffer_handle /*out*/); void waitForFrameLocked(DataCallbackMsg msgFrame, std::unique_lock
&l); void openEmptyDeviceSession(const std::string &name, sp
provider, sp
*session /*out*/, camera_metadata_t **staticMeta /*out*/); void castSession(const sp
&session, int32_t deviceVersion, sp
*session3_3 /*out*/, sp
*session3_4 /*out*/); void createStreamConfiguration(const ::android::hardware::hidl_vec
& streams3_2, StreamConfigurationMode configMode, ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2, ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4); void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion, sp
provider, const AvailableStream *previewThreshold, const std::unordered_set
& physicalIds, sp
*session3_4 /*out*/, V3_2::Stream* previewStream /*out*/, device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/, bool *supportsPartialResults /*out*/, uint32_t *partialResultCount /*out*/); void configurePreviewStream(const std::string &name, int32_t deviceVersion, sp
provider, const AvailableStream *previewThreshold, sp
*session /*out*/, V3_2::Stream *previewStream /*out*/, HalStreamConfiguration *halStreamConfig /*out*/, bool *supportsPartialResults /*out*/, uint32_t *partialResultCount /*out*/); static Status getAvailableOutputStreams(camera_metadata_t *staticMeta, std::vector
&outputStreams, const AvailableStream *threshold = nullptr); static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta); static Status isLogicalMultiCamera(camera_metadata_t *staticMeta); static Status getPhysicalCameraIds(camera_metadata_t *staticMeta, std::unordered_set
*physicalIds/*out*/); static Status getSupportedKeys(camera_metadata_t *staticMeta, uint32_t tagId, std::unordered_set
*requestIDs/*out*/); static void constructFilteredSettings(const sp
& session, const std::unordered_set
& availableKeys, RequestTemplate reqTemplate, android::hardware::camera::common::V1_0::helper::CameraMetadata* defaultSettings/*out*/, android::hardware::camera::common::V1_0::helper::CameraMetadata* filteredSettings /*out*/); static Status pickConstrainedModeSize(camera_metadata_t *staticMeta, AvailableStream &hfrStream); static Status isZSLModeAvailable(camera_metadata_t *staticMeta); static Status getZSLInputOutputMap(camera_metadata_t *staticMeta, std::vector
&inputOutputMap); static Status findLargestSize( const std::vector
&streamSizes, int32_t format, AvailableStream &result); static Status isAutoFocusModeAvailable( CameraParameters &cameraParams, const char *mode) ; protected: // In-flight queue for tracking completion of capture requests. struct InFlightRequest { // Set by notify() SHUTTER call. nsecs_t shutterTimestamp; bool errorCodeValid; ErrorCode errorCode; //Is partial result supported bool usePartialResult; //Partial result count expected uint32_t numPartialResults; // Message queue std::shared_ptr
resultQueue; // Set by process_capture_result call with valid metadata bool haveResultMetadata; // Decremented by calls to process_capture_result with valid output // and input buffers ssize_t numBuffersLeft; // A 64bit integer to index the frame number associated with this result. int64_t frameNumber; // The partial result count (index) for this capture result. int32_t partialResultCount; // For buffer drop errors, the stream ID for the stream that lost a buffer. // Otherwise -1. int32_t errorStreamId; // If this request has any input buffer bool hasInputBuffer; // Result metadata ::android::hardware::camera::common::V1_0::helper::CameraMetadata collectedResult; // Buffers are added by process_capture_result when output buffers // return from HAL but framework. ::android::Vector
resultOutputBuffers; InFlightRequest() : shutterTimestamp(0), errorCodeValid(false), errorCode(ErrorCode::ERROR_BUFFER), usePartialResult(false), numPartialResults(0), resultQueue(nullptr), haveResultMetadata(false), numBuffersLeft(0), frameNumber(0), partialResultCount(0), errorStreamId(-1), hasInputBuffer(false) {} InFlightRequest(ssize_t numBuffers, bool hasInput, bool partialResults, uint32_t partialCount, std::shared_ptr
queue = nullptr) : shutterTimestamp(0), errorCodeValid(false), errorCode(ErrorCode::ERROR_BUFFER), usePartialResult(partialResults), numPartialResults(partialCount), resultQueue(queue), haveResultMetadata(false), numBuffersLeft(numBuffers), frameNumber(0), partialResultCount(0), errorStreamId(-1), hasInputBuffer(hasInput) {} }; // Map from frame number to the in-flight request state typedef ::android::KeyedVector
InFlightMap; std::mutex mLock; // Synchronize access to member variables std::condition_variable mResultCondition; // Condition variable for incoming results InFlightMap mInflightMap; // Map of all inflight requests DataCallbackMsg mDataMessageTypeReceived; // Most recent message type received through data callbacks uint32_t mVideoBufferIndex; // Buffer index of the most recent video buffer uint32_t mVideoData; // Buffer data of the most recent video buffer hidl_handle mVideoNativeHandle; // Most recent video buffer native handle NotifyCallbackMsg mNotifyMessage; // Current notification message std::mutex mTorchLock; // Synchronize access to torch status std::condition_variable mTorchCond; // Condition variable for torch status TorchModeStatus mTorchStatus; // Current torch status // Holds camera registered buffers std::unordered_map
> mMemoryPool; // Camera provider service sp
mProvider; // Camera provider type. std::string mProviderType; }; Return
CameraHidlTest::Camera1DeviceCb::notifyCallback( NotifyCallbackMsg msgType, int32_t ext1 __unused, int32_t ext2 __unused) { std::unique_lock
l(mParent->mLock); mParent->mNotifyMessage = msgType; mParent->mResultCondition.notify_one(); return Void(); } Return
CameraHidlTest::Camera1DeviceCb::registerMemory( const hidl_handle& descriptor, uint32_t bufferSize, uint32_t bufferCount) { if (descriptor->numFds != 1) { ADD_FAILURE() << "camera memory descriptor has" " numFds " << descriptor->numFds << " (expect 1)" ; return 0; } if (descriptor->data[0] < 0) { ADD_FAILURE() << "camera memory descriptor has" " FD " << descriptor->data[0] << " (expect >= 0)"; return 0; } sp<::android::MemoryHeapBase> pool = new ::android::MemoryHeapBase( descriptor->data[0], bufferSize*bufferCount, 0, 0); mParent->mMemoryPool.emplace(pool->getHeapID(), pool); return pool->getHeapID(); } Return
CameraHidlTest::Camera1DeviceCb::unregisterMemory(uint32_t memId) { if (mParent->mMemoryPool.count(memId) == 0) { ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId); ADD_FAILURE(); return Void(); } mParent->mMemoryPool.erase(memId); return Void(); } Return
CameraHidlTest::Camera1DeviceCb::dataCallback( DataCallbackMsg msgType __unused, uint32_t data __unused, uint32_t bufferIndex __unused, const CameraFrameMetadata& metadata __unused) { std::unique_lock
l(mParent->mLock); mParent->mDataMessageTypeReceived = msgType; mParent->mResultCondition.notify_one(); return Void(); } Return
CameraHidlTest::Camera1DeviceCb::dataCallbackTimestamp( DataCallbackMsg msgType, uint32_t data, uint32_t bufferIndex, int64_t timestamp __unused) { std::unique_lock
l(mParent->mLock); mParent->mDataMessageTypeReceived = msgType; mParent->mVideoBufferIndex = bufferIndex; if (mParent->mMemoryPool.count(data) == 0) { ADD_FAILURE() << "memory pool ID " << data << "not found"; } mParent->mVideoData = data; mParent->mResultCondition.notify_one(); return Void(); } Return
CameraHidlTest::Camera1DeviceCb::handleCallbackTimestamp( DataCallbackMsg msgType, const hidl_handle& frameData, uint32_t data __unused, uint32_t bufferIndex, int64_t timestamp __unused) { std::unique_lock
l(mParent->mLock); mParent->mDataMessageTypeReceived = msgType; mParent->mVideoBufferIndex = bufferIndex; if (mParent->mMemoryPool.count(data) == 0) { ADD_FAILURE() << "memory pool ID " << data << " not found"; } mParent->mVideoData = data; mParent->mVideoNativeHandle = frameData; mParent->mResultCondition.notify_one(); return Void(); } Return
CameraHidlTest::Camera1DeviceCb::handleCallbackTimestampBatch( DataCallbackMsg msgType, const hidl_vec
& batch) { std::unique_lock
l(mParent->mLock); for (auto& msg : batch) { mParent->mDataMessageTypeReceived = msgType; mParent->mVideoBufferIndex = msg.bufferIndex; if (mParent->mMemoryPool.count(msg.data) == 0) { ADD_FAILURE() << "memory pool ID " << msg.data << " not found"; } mParent->mVideoData = msg.data; mParent->mVideoNativeHandle = msg.frameData; mParent->mResultCondition.notify_one(); } return Void(); } Return
CameraHidlTest::DeviceCb::processCaptureResult_3_4( const hidl_vec
& results) { if (nullptr == mParent) { return Void(); } bool notify = false; std::unique_lock
l(mParent->mLock); for (size_t i = 0 ; i < results.size(); i++) { notify = processCaptureResultLocked(results[i].v3_2); } l.unlock(); if (notify) { mParent->mResultCondition.notify_one(); } return Void(); } Return
CameraHidlTest::DeviceCb::processCaptureResult( const hidl_vec
& results) { if (nullptr == mParent) { return Void(); } bool notify = false; std::unique_lock
l(mParent->mLock); for (size_t i = 0 ; i < results.size(); i++) { notify = processCaptureResultLocked(results[i]); } l.unlock(); if (notify) { mParent->mResultCondition.notify_one(); } return Void(); } bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& results) { bool notify = false; uint32_t frameNumber = results.frameNumber; if ((results.result.size() == 0) && (results.outputBuffers.size() == 0) && (results.inputBuffer.buffer == nullptr) && (results.fmqResultSize == 0)) { ALOGE("%s: No result data provided by HAL for frame %d result count: %d", __func__, frameNumber, (int) results.fmqResultSize); ADD_FAILURE(); return notify; } ssize_t idx = mParent->mInflightMap.indexOfKey(frameNumber); if (::android::NAME_NOT_FOUND == idx) { ALOGE("%s: Unexpected frame number! received: %u", __func__, frameNumber); ADD_FAILURE(); return notify; } bool isPartialResult = false; bool hasInputBufferInRequest = false; InFlightRequest *request = mParent->mInflightMap.editValueAt(idx); ::android::hardware::camera::device::V3_2::CameraMetadata resultMetadata; size_t resultSize = 0; if (results.fmqResultSize > 0) { resultMetadata.resize(results.fmqResultSize); if (request->resultQueue == nullptr) { ADD_FAILURE(); return notify; } if (!request->resultQueue->read(resultMetadata.data(), results.fmqResultSize)) { ALOGE("%s: Frame %d: Cannot read camera metadata from fmq," "size = %" PRIu64, __func__, frameNumber, results.fmqResultSize); ADD_FAILURE(); return notify; } resultSize = resultMetadata.size(); } else if (results.result.size() > 0) { resultMetadata.setToExternal(const_cast
( results.result.data()), results.result.size()); resultSize = resultMetadata.size(); } if (!request->usePartialResult && (resultSize > 0) && (results.partialResult != 1)) { ALOGE("%s: Result is malformed for frame %d: partial_result %u " "must be 1 if partial result is not supported", __func__, frameNumber, results.partialResult); ADD_FAILURE(); return notify; } if (results.partialResult != 0) { request->partialResultCount = results.partialResult; } // Check if this result carries only partial metadata if (request->usePartialResult && (resultSize > 0)) { if ((results.partialResult > request->numPartialResults) || (results.partialResult < 1)) { ALOGE("%s: Result is malformed for frame %d: partial_result %u" " must be in the range of [1, %d] when metadata is " "included in the result", __func__, frameNumber, results.partialResult, request->numPartialResults); ADD_FAILURE(); return notify; } request->collectedResult.append( reinterpret_cast
( resultMetadata.data())); isPartialResult = (results.partialResult < request->numPartialResults); } else if (resultSize > 0) { request->collectedResult.append(reinterpret_cast
( resultMetadata.data())); isPartialResult = false; } hasInputBufferInRequest = request->hasInputBuffer; // Did we get the (final) result metadata for this capture? if ((resultSize > 0) && !isPartialResult) { if (request->haveResultMetadata) { ALOGE("%s: Called multiple times with metadata for frame %d", __func__, frameNumber); ADD_FAILURE(); return notify; } request->haveResultMetadata = true; request->collectedResult.sort(); } uint32_t numBuffersReturned = results.outputBuffers.size(); if (results.inputBuffer.buffer != nullptr) { if (hasInputBufferInRequest) { numBuffersReturned += 1; } else { ALOGW("%s: Input buffer should be NULL if there is no input" " buffer sent in the request", __func__); } } request->numBuffersLeft -= numBuffersReturned; if (request->numBuffersLeft < 0) { ALOGE("%s: Too many buffers returned for frame %d", __func__, frameNumber); ADD_FAILURE(); return notify; } request->resultOutputBuffers.appendArray(results.outputBuffers.data(), results.outputBuffers.size()); // If shutter event is received notify the pending threads. if (request->shutterTimestamp != 0) { notify = true; } return notify; } Return
CameraHidlTest::DeviceCb::notify( const hidl_vec
& messages) { std::lock_guard
l(mParent->mLock); for (size_t i = 0; i < messages.size(); i++) { ssize_t idx = mParent->mInflightMap.indexOfKey( messages[i].msg.shutter.frameNumber); if (::android::NAME_NOT_FOUND == idx) { ALOGE("%s: Unexpected frame number! received: %u", __func__, messages[i].msg.shutter.frameNumber); ADD_FAILURE(); break; } InFlightRequest *r = mParent->mInflightMap.editValueAt(idx); switch(messages[i].type) { case MsgType::ERROR: if (ErrorCode::ERROR_DEVICE == messages[i].msg.error.errorCode) { ALOGE("%s: Camera reported serious device error", __func__); ADD_FAILURE(); } else { r->errorCodeValid = true; r->errorCode = messages[i].msg.error.errorCode; r->errorStreamId = messages[i].msg.error.errorStreamId; } break; case MsgType::SHUTTER: r->shutterTimestamp = messages[i].msg.shutter.timestamp; break; default: ALOGE("%s: Unsupported notify message %d", __func__, messages[i].type); ADD_FAILURE(); break; } } mParent->mResultCondition.notify_one(); return Void(); } hidl_vec
CameraHidlTest::getCameraDeviceNames(sp
provider) { std::vector
cameraDeviceNames; Return
ret; ret = provider->getCameraIdList( [&](auto status, const auto& idList) { ALOGI("getCameraIdList returns status:%d", (int)status); for (size_t i = 0; i < idList.size(); i++) { ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str()); } ASSERT_EQ(Status::OK, status); for (const auto& id : idList) { cameraDeviceNames.push_back(id); } }); if (!ret.isOk()) { ADD_FAILURE(); } // External camera devices are reported through cameraDeviceStatusChange struct ProviderCb : public ICameraProviderCallback { virtual Return
cameraDeviceStatusChange( const hidl_string& devName, CameraDeviceStatus newStatus) override { ALOGI("camera device status callback name %s, status %d", devName.c_str(), (int) newStatus); if (newStatus == CameraDeviceStatus::PRESENT) { externalCameraDeviceNames.push_back(devName); } return Void(); } virtual Return
torchModeStatusChange( const hidl_string&, TorchModeStatus) override { return Void(); } std::vector
externalCameraDeviceNames; }; sp
cb = new ProviderCb; auto status = mProvider->setCallback(cb); for (const auto& devName : cb->externalCameraDeviceNames) { if (cameraDeviceNames.end() == std::find( cameraDeviceNames.begin(), cameraDeviceNames.end(), devName)) { cameraDeviceNames.push_back(devName); } } hidl_vec
retList(cameraDeviceNames.size()); for (size_t i = 0; i < cameraDeviceNames.size(); i++) { retList[i] = cameraDeviceNames[i]; } return retList; } // Test devices with first_api_level >= P does not advertise device@1.0 TEST_F(CameraHidlTest, noHal1AfterP) { constexpr int32_t HAL1_PHASE_OUT_API_LEVEL = 28; int32_t firstApiLevel = property_get_int32("ro.product.first_api_level", /*default*/-1); if (firstApiLevel < 0) { firstApiLevel = property_get_int32("ro.build.version.sdk", /*default*/-1); } ASSERT_GT(firstApiLevel, 0); // first_api_level must exist if (firstApiLevel >= HAL1_PHASE_OUT_API_LEVEL) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); ASSERT_NE(deviceVersion, 0); // Must be a valid device version ASSERT_NE(deviceVersion, CAMERA_DEVICE_API_VERSION_1_0); // Must not be device@1.0 } } } // Test if ICameraProvider::isTorchModeSupported returns Status::OK TEST_F(CameraHidlTest, isTorchModeSupported) { Return
ret; ret = mProvider->isSetTorchModeSupported([&](auto status, bool support) { ALOGI("isSetTorchModeSupported returns status:%d supported:%d", (int)status, support); ASSERT_EQ(Status::OK, status); }); ASSERT_TRUE(ret.isOk()); } // TODO: consider removing this test if getCameraDeviceNames() has the same coverage TEST_F(CameraHidlTest, getCameraIdList) { Return
ret; ret = mProvider->getCameraIdList([&](auto status, const auto& idList) { ALOGI("getCameraIdList returns status:%d", (int)status); for (size_t i = 0; i < idList.size(); i++) { ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str()); } ASSERT_EQ(Status::OK, status); }); ASSERT_TRUE(ret.isOk()); } // Test if ICameraProvider::getVendorTags returns Status::OK TEST_F(CameraHidlTest, getVendorTags) { Return
ret; ret = mProvider->getVendorTags([&](auto status, const auto& vendorTagSecs) { ALOGI("getVendorTags returns status:%d numSections %zu", (int)status, vendorTagSecs.size()); for (size_t i = 0; i < vendorTagSecs.size(); i++) { ALOGI("Vendor tag section %zu name %s", i, vendorTagSecs[i].sectionName.c_str()); for (size_t j = 0; j < vendorTagSecs[i].tags.size(); j++) { const auto& tag = vendorTagSecs[i].tags[j]; ALOGI("Vendor tag id %u name %s type %d", tag.tagId, tag.tagName.c_str(), (int)tag.tagType); } } ASSERT_EQ(Status::OK, status); }); ASSERT_TRUE(ret.isOk()); } // Test if ICameraProvider::setCallback returns Status::OK TEST_F(CameraHidlTest, setCallback) { struct ProviderCb : public ICameraProviderCallback { virtual Return
cameraDeviceStatusChange( const hidl_string& cameraDeviceName, CameraDeviceStatus newStatus) override { ALOGI("camera device status callback name %s, status %d", cameraDeviceName.c_str(), (int) newStatus); return Void(); } virtual Return
torchModeStatusChange( const hidl_string& cameraDeviceName, TorchModeStatus newStatus) override { ALOGI("Torch mode status callback name %s, status %d", cameraDeviceName.c_str(), (int) newStatus); return Void(); } }; sp
cb = new ProviderCb; auto status = mProvider->setCallback(cb); ASSERT_TRUE(status.isOk()); ASSERT_EQ(Status::OK, status); status = mProvider->setCallback(nullptr); ASSERT_TRUE(status.isOk()); ASSERT_EQ(Status::OK, status); } // Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device TEST_F(CameraHidlTest, getCameraDeviceInterface) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: case CAMERA_DEVICE_API_VERSION_3_2: { Return
ret; ret = mProvider->getCameraDeviceInterface_V3_x( name, [&](auto status, const auto& device3_x) { ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device3_x, nullptr); }); ASSERT_TRUE(ret.isOk()); } break; case CAMERA_DEVICE_API_VERSION_1_0: { Return
ret; ret = mProvider->getCameraDeviceInterface_V1_x( name, [&](auto status, const auto& device1) { ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device1, nullptr); }); ASSERT_TRUE(ret.isOk()); } break; default: { ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); ADD_FAILURE(); } break; } } } // Verify that the device resource cost can be retrieved and the values are // sane. TEST_F(CameraHidlTest, getResourceCost) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: case CAMERA_DEVICE_API_VERSION_3_2: { ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x; ALOGI("getResourceCost: Testing camera device %s", name.c_str()); Return
ret; ret = mProvider->getCameraDeviceInterface_V3_x( name, [&](auto status, const auto& device) { ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); device3_x = device; }); ASSERT_TRUE(ret.isOk()); ret = device3_x->getResourceCost([&](auto status, const auto& resourceCost) { ALOGI("getResourceCost returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ALOGI(" Resource cost is %d", resourceCost.resourceCost); ASSERT_LE(resourceCost.resourceCost, 100u); for (const auto& name : resourceCost.conflictingDevices) { ALOGI(" Conflicting device: %s", name.c_str()); } }); ASSERT_TRUE(ret.isOk()); } break; case CAMERA_DEVICE_API_VERSION_1_0: { ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; ALOGI("getResourceCost: Testing camera device %s", name.c_str()); Return
ret; ret = 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; }); ASSERT_TRUE(ret.isOk()); ret = device1->getResourceCost([&](auto status, const auto& resourceCost) { ALOGI("getResourceCost returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ALOGI(" Resource cost is %d", resourceCost.resourceCost); ASSERT_LE(resourceCost.resourceCost, 100u); for (const auto& name : resourceCost.conflictingDevices) { ALOGI(" Conflicting device: %s", name.c_str()); } }); ASSERT_TRUE(ret.isOk()); } break; default: { ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); ADD_FAILURE(); } break; } } } // Verify that the static camera info can be retrieved // successfully. TEST_F(CameraHidlTest, getCameraInfo) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == 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()); Return
ret; ret = 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; }); ASSERT_TRUE(ret.isOk()); ret = device1->getCameraInfo([&](auto status, const auto& info) { ALOGI("getCameraInfo returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); switch (info.orientation) { case 0: case 90: case 180: case 270: // Expected cases ALOGI("camera orientation: %d", info.orientation); break; default: FAIL() << "Unexpected camera orientation:" << info.orientation; } switch (info.facing) { case CameraFacing::BACK: case CameraFacing::FRONT: case CameraFacing::EXTERNAL: // Expected cases ALOGI("camera facing: %d", info.facing); break; default: FAIL() << "Unexpected camera facing:" << static_cast
(info.facing); } }); ASSERT_TRUE(ret.isOk()); } } } // Check whether preview window can be configured TEST_F(CameraHidlTest, setPreviewWindow) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); Return
ret; ret = device1->close(); ASSERT_TRUE(ret.isOk()); } } } // Verify that setting preview window fails in case device is not open TEST_F(CameraHidlTest, setPreviewWindowInvalid) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == 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()); Return
ret; ret = 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; }); ASSERT_TRUE(ret.isOk()); Return
returnStatus = device1->setPreviewWindow(nullptr); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OPERATION_NOT_SUPPORTED, returnStatus); } } } // Start and stop preview checking whether it gets enabled in between. TEST_F(CameraHidlTest, startStopPreview) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); startPreview(device1); Return
returnBoolStatus = device1->previewEnabled(); ASSERT_TRUE(returnBoolStatus.isOk()); ASSERT_TRUE(returnBoolStatus); stopPreviewAndClose(device1); } } } // Start preview without active preview window. Preview should start as soon // as a valid active window gets configured. TEST_F(CameraHidlTest, startStopPreviewDelayed) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); Return
returnStatus = device1->setPreviewWindow(nullptr); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); startPreview(device1); sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); // Preview should get enabled now Return
returnBoolStatus = device1->previewEnabled(); ASSERT_TRUE(returnBoolStatus.isOk()); ASSERT_TRUE(returnBoolStatus); stopPreviewAndClose(device1); } } } // Verify that image capture behaves as expected along with preview callbacks. TEST_F(CameraHidlTest, takePicture) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); { std::unique_lock
l(mLock); mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; } enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); startPreview(device1); { std::unique_lock
l(mLock); waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l); } disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); enableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE, device1); { std::unique_lock
l(mLock); mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; } Return
returnStatus = device1->takePicture(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); { std::unique_lock
l(mLock); waitForFrameLocked(DataCallbackMsg::COMPRESSED_IMAGE, l); } disableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE, device1); stopPreviewAndClose(device1); } } } // Image capture should fail in case preview didn't get enabled first. TEST_F(CameraHidlTest, takePictureFail) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); Return
returnStatus = device1->takePicture(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_NE(Status::OK, returnStatus); Return
ret = device1->close(); ASSERT_TRUE(ret.isOk()); } } } // Verify that image capture can be cancelled. TEST_F(CameraHidlTest, cancelPicture) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); startPreview(device1); Return
returnStatus = device1->takePicture(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); returnStatus = device1->cancelPicture(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); stopPreviewAndClose(device1); } } } // Image capture cancel is a no-op when image capture is not running. TEST_F(CameraHidlTest, cancelPictureNOP) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); startPreview(device1); Return
returnStatus = device1->cancelPicture(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); stopPreviewAndClose(device1); } } } // Test basic video recording. TEST_F(CameraHidlTest, startStopRecording) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); { std::unique_lock
l(mLock); mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; } enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); startPreview(device1); { std::unique_lock
l(mLock); waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l); mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; mVideoBufferIndex = UINT32_MAX; } disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); bool videoMetaEnabled = false; Return
returnStatus = device1->storeMetaDataInBuffers(true); ASSERT_TRUE(returnStatus.isOk()); // It is allowed for devices to not support this feature ASSERT_TRUE((Status::OK == returnStatus) || (Status::OPERATION_NOT_SUPPORTED == returnStatus)); if (Status::OK == returnStatus) { videoMetaEnabled = true; } enableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, device1); Return
returnBoolStatus = device1->recordingEnabled(); ASSERT_TRUE(returnBoolStatus.isOk()); ASSERT_FALSE(returnBoolStatus); returnStatus = device1->startRecording(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); { std::unique_lock
l(mLock); waitForFrameLocked(DataCallbackMsg::VIDEO_FRAME, l); ASSERT_NE(UINT32_MAX, mVideoBufferIndex); disableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, device1); } returnBoolStatus = device1->recordingEnabled(); ASSERT_TRUE(returnBoolStatus.isOk()); ASSERT_TRUE(returnBoolStatus); Return
ret; if (videoMetaEnabled) { ret = device1->releaseRecordingFrameHandle(mVideoData, mVideoBufferIndex, mVideoNativeHandle); ASSERT_TRUE(ret.isOk()); } else { ret = device1->releaseRecordingFrame(mVideoData, mVideoBufferIndex); ASSERT_TRUE(ret.isOk()); } ret = device1->stopRecording(); ASSERT_TRUE(ret.isOk()); stopPreviewAndClose(device1); } } } // It shouldn't be possible to start recording without enabling preview first. TEST_F(CameraHidlTest, startRecordingFail) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); Return
returnBoolStatus = device1->recordingEnabled(); ASSERT_TRUE(returnBoolStatus.isOk()); ASSERT_FALSE(returnBoolStatus); Return
returnStatus = device1->startRecording(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_NE(Status::OK, returnStatus); Return
ret = device1->close(); ASSERT_TRUE(ret.isOk()); } } } // Check autofocus support if available. TEST_F(CameraHidlTest, autoFocus) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); std::vector
focusModes = {CameraParameters::FOCUS_MODE_AUTO, CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE, CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO}; for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); CameraParameters cameraParams; getParameters(device1, &cameraParams /*out*/); if (Status::OK != isAutoFocusModeAvailable(cameraParams, CameraParameters::FOCUS_MODE_AUTO)) { Return
ret = device1->close(); ASSERT_TRUE(ret.isOk()); continue; } sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); startPreview(device1); enableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1); for (auto& iter : focusModes) { if (Status::OK != isAutoFocusModeAvailable(cameraParams, iter)) { continue; } cameraParams.set(CameraParameters::KEY_FOCUS_MODE, iter); setParameters(device1, cameraParams); { std::unique_lock
l(mLock); mNotifyMessage = NotifyCallbackMsg::ERROR; } Return
returnStatus = device1->autoFocus(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); { std::unique_lock
l(mLock); while (NotifyCallbackMsg::FOCUS != mNotifyMessage) { auto timeout = std::chrono::system_clock::now() + std::chrono::seconds(kAutoFocusTimeoutSec); ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout)); } } } disableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1); stopPreviewAndClose(device1); } } } // In case autofocus is supported verify that it can be cancelled. TEST_F(CameraHidlTest, cancelAutoFocus) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); CameraParameters cameraParams; getParameters(device1, &cameraParams /*out*/); if (Status::OK != isAutoFocusModeAvailable(cameraParams, CameraParameters::FOCUS_MODE_AUTO)) { Return
ret = device1->close(); ASSERT_TRUE(ret.isOk()); continue; } // It should be fine to call before preview starts. ASSERT_EQ(Status::OK, device1->cancelAutoFocus()); sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); startPreview(device1); // It should be fine to call after preview starts too. Return
returnStatus = device1->cancelAutoFocus(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); returnStatus = device1->autoFocus(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); returnStatus = device1->cancelAutoFocus(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); stopPreviewAndClose(device1); } } } // Check whether face detection is available and try to enable&disable. TEST_F(CameraHidlTest, sendCommandFaceDetection) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); CameraParameters cameraParams; getParameters(device1, &cameraParams /*out*/); int32_t hwFaces = cameraParams.getInt(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW); int32_t swFaces = cameraParams.getInt(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW); if ((0 >= hwFaces) && (0 >= swFaces)) { Return
ret = device1->close(); ASSERT_TRUE(ret.isOk()); continue; } sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); startPreview(device1); if (0 < hwFaces) { Return
returnStatus = device1->sendCommand( CommandType::START_FACE_DETECTION, CAMERA_FACE_DETECTION_HW, 0); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); // TODO(epeev) : Enable and check for face notifications returnStatus = device1->sendCommand(CommandType::STOP_FACE_DETECTION, CAMERA_FACE_DETECTION_HW, 0); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); } if (0 < swFaces) { Return
returnStatus = device1->sendCommand( CommandType::START_FACE_DETECTION, CAMERA_FACE_DETECTION_SW, 0); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); // TODO(epeev) : Enable and check for face notifications returnStatus = device1->sendCommand(CommandType::STOP_FACE_DETECTION, CAMERA_FACE_DETECTION_SW, 0); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); } stopPreviewAndClose(device1); } } } // Check whether smooth zoom is available and try to enable&disable. TEST_F(CameraHidlTest, sendCommandSmoothZoom) { hidl_vec
cameraDeviceNames = getCameraDeviceNames(mProvider); for (const auto& name : cameraDeviceNames) { if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); CameraParameters cameraParams; getParameters(device1, &cameraParams /*out*/); const char* smoothZoomStr = cameraParams.get(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED); bool smoothZoomSupported = ((nullptr != smoothZoomStr) && (strcmp(smoothZoomStr, CameraParameters::TRUE) == 0)) ? true : false; if (!smoothZoomSupported) { Return
ret = device1->close(); ASSERT_TRUE(ret.isOk()); continue; } int32_t maxZoom = cameraParams.getInt(CameraParameters::KEY_MAX_ZOOM); ASSERT_TRUE(0 < maxZoom); sp
bufferItemConsumer; sp
bufferHandler; setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); startPreview(device1); setParameters(device1, cameraParams); Return