HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Android 10
|
10.0.0_r6
下载
查看原文件
收藏
根目录
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
#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_bitfield; 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::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::camera::metadata::V3_4::CameraMetadataEnumAndroidSensorInfoColorFilterArrangement; using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag; using ::android::hardware::camera::device::V3_4::PhysicalCameraMetadata; 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; const int64_t kBufferReturnTimeoutSec = 1; struct AvailableStream { int32_t width; int32_t height; int32_t format; }; struct AvailableZSLInputOutput { int32_t inputFormat; int32_t outputFormat; }; enum ReprocessType { PRIV_REPROCESS, YUV_REPROCESS, }; namespace { // "device@
/legacy/
" const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)"; const int CAMERA_DEVICE_API_VERSION_3_5 = 0x305; 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_5 = "3.5"; 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_5) == 0) { return CAMERA_DEVICE_API_VERSION_3_5; } else 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; } void getFirstApiLevel(/*out*/int32_t* outApiLevel) { 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 *outApiLevel = firstApiLevel; return; } } // 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)); castProvider(mProvider, &mProvider2_5); notifyDeviceState(provider::V2_5::DeviceState::NORMAL); } virtual void TearDown() override {} hidl_vec
getCameraDeviceNames(sp
provider); struct EmptyDeviceCb : public V3_5::ICameraDeviceCallback { virtual Return
processCaptureResult( const hidl_vec
& /*results*/) override { ALOGI("processCaptureResult callback"); ADD_FAILURE(); // Empty callback should not reach here return Void(); } virtual Return
processCaptureResult_3_4( const hidl_vec
& /*results*/) override { ALOGI("processCaptureResult_3_4 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(); } virtual Return
requestStreamBuffers( const hidl_vec
&, requestStreamBuffers_cb _hidl_cb) override { ALOGI("requestStreamBuffers callback"); // HAL might want to request buffer after configureStreams, but tests with EmptyDeviceCb // doesn't actually need to send capture requests, so just return an error. hidl_vec
emptyBufRets; _hidl_cb(V3_5::BufferRequestStatus::FAILED_UNKNOWN, emptyBufRets); return Void(); } virtual Return
returnStreamBuffers(const hidl_vec
&) override { ALOGI("returnStreamBuffers"); ADD_FAILURE(); // Empty callback should not reach here return Void(); } }; struct DeviceCb : public V3_5::ICameraDeviceCallback { DeviceCb(CameraHidlTest *parent, int deviceVersion, const camera_metadata_t *staticMeta) : mParent(parent), mDeviceVersion(deviceVersion) { mStaticMetadata = staticMeta; } Return
processCaptureResult_3_4( const hidl_vec
& results) override; Return
processCaptureResult(const hidl_vec
& results) override; Return
notify(const hidl_vec
& msgs) override; Return
requestStreamBuffers( const hidl_vec
& bufReqs, requestStreamBuffers_cb _hidl_cb) override; Return
returnStreamBuffers(const hidl_vec
& buffers) override; void setCurrentStreamConfig(const hidl_vec
& streams, const hidl_vec
& halStreams); void waitForBuffersReturned(); private: bool processCaptureResultLocked(const CaptureResult& results, hidl_vec
physicalCameraMetadata); CameraHidlTest *mParent; // Parent object int mDeviceVersion; android::hardware::camera::common::V1_0::helper::CameraMetadata mStaticMetadata; bool hasOutstandingBuffersLocked(); /* members for requestStreamBuffers() and returnStreamBuffers()*/ std::mutex mLock; // protecting members below bool mUseHalBufManager = false; hidl_vec
mStreams; hidl_vec
mHalStreams; uint64_t mNextBufferId = 1; using OutstandingBuffers = std::unordered_map
; // size == mStreams.size(). Tracking each streams outstanding buffers std::vector
mOutstandingBufferIds; std::condition_variable mFlushedCondition; }; 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 notifyDeviceState(::android::hardware::camera::provider::V2_5::DeviceState newState); 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*/, ::android::sp
*device = nullptr/*out*/); void castProvider(const sp
&provider, sp
*provider2_5 /*out*/); void castSession(const sp
&session, int32_t deviceVersion, sp
*session3_3 /*out*/, sp
*session3_4 /*out*/, sp
*session3_5 /*out*/); void castDevice(const sp
&device, int32_t deviceVersion, sp
*device3_5/*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, ::android::hardware::camera::device::V3_5::StreamConfiguration *config3_5, uint32_t jpegBufferSize = 0); void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion, sp
provider, const AvailableStream *previewThreshold, const std::unordered_set
& physicalIds, sp
*session3_4 /*out*/, sp
*session3_5 /*out*/, V3_2::Stream* previewStream /*out*/, device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/, bool *supportsPartialResults /*out*/, uint32_t *partialResultCount /*out*/, bool *useHalBufManager /*out*/, sp
*cb /*out*/, uint32_t streamConfigCounter = 0, bool allowUnsupport = false); 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*/, bool *useHalBufManager /*out*/, sp
*cb /*out*/, uint32_t streamConfigCounter = 0); void verifyLogicalCameraMetadata(const std::string& cameraName, const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device, const CameraMetadata& chars, int deviceVersion, const hidl_vec
& deviceNames); void verifyCameraCharacteristics(Status status, const CameraMetadata& chars); void verifyRecommendedConfigs(const CameraMetadata& metadata); void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion); void verifyMonochromeCameraResult( const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata); void verifyStreamCombination(sp
cameraDevice3_5, const ::android::hardware::camera::device::V3_4::StreamConfiguration &config3_4, bool expectedStatus, bool expectStreamCombQuery); void verifyLogicalCameraResult(const camera_metadata_t* staticMetadata, const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& resultMetadata); void verifyBuffersReturned(sp
session, int deviceVerison, int32_t streamId, sp
cb, uint32_t streamConfigCounter = 0); void verifyBuffersReturned(sp
session, hidl_vec
streamIds, sp
cb, uint32_t streamConfigCounter = 0); void verifySessionReconfigurationQuery(sp
session3_5, camera_metadata* oldSessionParams, camera_metadata* newSessionParams); bool isDepthOnly(camera_metadata_t* staticMeta); static Status getAvailableOutputStreams(camera_metadata_t *staticMeta, std::vector
&outputStreams, const AvailableStream *threshold = nullptr); static Status getJpegBufferSize(camera_metadata_t *staticMeta, uint32_t* outBufSize); static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta); static Status isLogicalMultiCamera(const camera_metadata_t *staticMeta); static Status getPhysicalCameraIds(const 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 fillOutputStreams(camera_metadata_ro_entry_t* entry, std::vector
& outputStreams, const AvailableStream *threshold = nullptr, const int32_t availableConfigOutputTag = 0u); 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(const camera_metadata_t *staticMeta); static Status isZSLModeAvailable(const camera_metadata_t *staticMeta, ReprocessType reprocType); 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) ; static Status isMonochromeCamera(const camera_metadata_t *staticMeta); 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; sp<::android::hardware::camera::provider::V2_5::ICameraProvider> mProvider2_5; // 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, results[i].physicalCameraMetadata); } 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); ::android::hardware::hidl_vec
noPhysMetadata; for (size_t i = 0 ; i < results.size(); i++) { notify = processCaptureResultLocked(results[i], noPhysMetadata); } l.unlock(); if (notify) { mParent->mResultCondition.notify_one(); } return Void(); } bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& results, hidl_vec
physicalCameraMetadata) { 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; } std::vector<::android::hardware::camera::device::V3_2::CameraMetadata> physResultMetadata; physResultMetadata.resize(physicalCameraMetadata.size()); for (size_t i = 0; i < physicalCameraMetadata.size(); i++) { physResultMetadata[i].resize(physicalCameraMetadata[i].fmqMetadataSize); if (!request->resultQueue->read(physResultMetadata[i].data(), physicalCameraMetadata[i].fmqMetadataSize)) { ALOGE("%s: Frame %d: Cannot read physical camera metadata from fmq," "size = %" PRIu64, __func__, frameNumber, physicalCameraMetadata[i].fmqMetadataSize); 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(); // Verify final result metadata bool isAtLeast_3_5 = mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_5; if (isAtLeast_3_5) { auto staticMetadataBuffer = mStaticMetadata.getAndLock(); bool isMonochrome = Status::OK == CameraHidlTest::isMonochromeCamera(staticMetadataBuffer); if (isMonochrome) { mParent->verifyMonochromeCameraResult(request->collectedResult); } // Verify logical camera result metadata bool isLogicalCamera = Status::OK == CameraHidlTest::isLogicalMultiCamera(staticMetadataBuffer); if (isLogicalCamera) { mParent->verifyLogicalCameraResult(staticMetadataBuffer, request->collectedResult); } mStaticMetadata.unlock(staticMetadataBuffer); } } 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; } if (mUseHalBufManager) { // Don't return buffers of bufId 0 (empty buffer) std::vector
buffers; for (const auto& sb : results.outputBuffers) { if (sb.bufferId != 0) { buffers.push_back(sb); } } returnStreamBuffers(buffers); } return notify; } void CameraHidlTest::DeviceCb::setCurrentStreamConfig( const hidl_vec
& streams, const hidl_vec
& halStreams) { ASSERT_EQ(streams.size(), halStreams.size()); ASSERT_NE(streams.size(), 0); for (size_t i = 0; i < streams.size(); i++) { ASSERT_EQ(streams[i].id, halStreams[i].id); } std::lock_guard
l(mLock); mUseHalBufManager = true; mStreams = streams; mHalStreams = halStreams; mOutstandingBufferIds.clear(); for (size_t i = 0; i < streams.size(); i++) { mOutstandingBufferIds.emplace_back(); } } bool CameraHidlTest::DeviceCb::hasOutstandingBuffersLocked() { if (!mUseHalBufManager) { return false; } for (const auto& outstandingBuffers : mOutstandingBufferIds) { if (!outstandingBuffers.empty()) { return true; } } return false; } void CameraHidlTest::DeviceCb::waitForBuffersReturned() { std::unique_lock
lk(mLock); if (hasOutstandingBuffersLocked()) { auto timeout = std::chrono::seconds(kBufferReturnTimeoutSec); auto st = mFlushedCondition.wait_for(lk, timeout); ASSERT_NE(std::cv_status::timeout, st); } } 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(); } Return
CameraHidlTest::DeviceCb::requestStreamBuffers( const hidl_vec
& bufReqs, requestStreamBuffers_cb _hidl_cb) { using V3_5::BufferRequestStatus; using V3_5::StreamBufferRet; using V3_5::StreamBufferRequestError; hidl_vec
bufRets; std::unique_lock
l(mLock); if (!mUseHalBufManager) { ALOGE("%s: Camera does not support HAL buffer management", __FUNCTION__); ADD_FAILURE(); _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets); return Void(); } if (bufReqs.size() > mStreams.size()) { ALOGE("%s: illegal buffer request: too many requests!", __FUNCTION__); ADD_FAILURE(); _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets); return Void(); } std::vector
indexes(bufReqs.size()); for (size_t i = 0; i < bufReqs.size(); i++) { bool found = false; for (size_t idx = 0; idx < mStreams.size(); idx++) { if (bufReqs[i].streamId == mStreams[idx].id) { found = true; indexes[i] = idx; break; } } if (!found) { ALOGE("%s: illegal buffer request: unknown streamId %d!", __FUNCTION__, bufReqs[i].streamId); ADD_FAILURE(); _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets); return Void(); } } bool allStreamOk = true; bool atLeastOneStreamOk = false; bufRets.resize(bufReqs.size()); for (size_t i = 0; i < bufReqs.size(); i++) { int32_t idx = indexes[i]; const auto& stream = mStreams[idx]; const auto& halStream = mHalStreams[idx]; const V3_5::BufferRequest& bufReq = bufReqs[i]; if (mOutstandingBufferIds[idx].size() + bufReq.numBuffersRequested > halStream.maxBuffers) { bufRets[i].streamId = stream.id; bufRets[i].val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED); allStreamOk = false; continue; } hidl_vec
tmpRetBuffers(bufReq.numBuffersRequested); for (size_t j = 0; j < bufReq.numBuffersRequested; j++) { hidl_handle buffer_handle; mParent->allocateGraphicBuffer(stream.width, stream.height, android_convertGralloc1To0Usage( halStream.producerUsage, halStream.consumerUsage), halStream.overrideFormat, &buffer_handle); tmpRetBuffers[j] = {stream.id, mNextBufferId, buffer_handle, BufferStatus::OK, nullptr, nullptr}; mOutstandingBufferIds[idx].insert(std::make_pair(mNextBufferId++, buffer_handle)); } atLeastOneStreamOk = true; bufRets[i].streamId = stream.id; bufRets[i].val.buffers(std::move(tmpRetBuffers)); } if (allStreamOk) { _hidl_cb(BufferRequestStatus::OK, bufRets); } else if (atLeastOneStreamOk) { _hidl_cb(BufferRequestStatus::FAILED_PARTIAL, bufRets); } else { _hidl_cb(BufferRequestStatus::FAILED_UNKNOWN, bufRets); } if (!hasOutstandingBuffersLocked()) { l.unlock(); mFlushedCondition.notify_one(); } return Void(); } Return
CameraHidlTest::DeviceCb::returnStreamBuffers( const hidl_vec
& buffers) { if (!mUseHalBufManager) { ALOGE("%s: Camera does not support HAL buffer management", __FUNCTION__); ADD_FAILURE(); } std::lock_guard
l(mLock); for (const auto& buf : buffers) { bool found = false; for (size_t idx = 0; idx < mOutstandingBufferIds.size(); idx++) { if (mStreams[idx].id == buf.streamId && mOutstandingBufferIds[idx].count(buf.bufferId) == 1) { mOutstandingBufferIds[idx].erase(buf.bufferId); // TODO: check do we need to close/delete native handle or assume we have enough // memory to run till the test finish? since we do not capture much requests (and // most of time one buffer is sufficient) found = true; break; } } if (found) { continue; } ALOGE("%s: unknown buffer ID %" PRIu64, __FUNCTION__, buf.bufferId); ADD_FAILURE(); } 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 = 0; getFirstApiLevel(&firstApiLevel); // all devices with first API level == 28 and <= 1GB of RAM must set low_ram // and thus be allowed to continue using HAL1 if ((firstApiLevel == HAL1_PHASE_OUT_API_LEVEL) && (property_get_bool("ro.config.low_ram", /*default*/ false))) { ALOGI("Hal1 allowed for low ram device"); return; } 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 // Also if first_api_level >= Q torch API must be supported. TEST_F(CameraHidlTest, isTorchModeSupported) { constexpr int32_t API_LEVEL_Q = 29; int32_t firstApiLevel = 0; getFirstApiLevel(&firstApiLevel); Return
ret; ret = mProvider->isSetTorchModeSupported([&](auto status, bool support) { ALOGI("isSetTorchModeSupported returns status:%d supported:%d", (int)status, support); ASSERT_EQ(Status::OK, status); if (firstApiLevel >= API_LEVEL_Q) { ASSERT_EQ(true, support); } }); 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_5: 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_5: 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