diff options
25 files changed, 451 insertions, 89 deletions
diff --git a/common/hal/common/hal_types.h b/common/hal/common/hal_types.h index 3bd188f..4fe1da0 100644 --- a/common/hal/common/hal_types.h +++ b/common/hal/common/hal_types.h @@ -302,6 +302,11 @@ struct Point { uint32_t y; }; +struct PointI { + int32_t x; + int32_t y; +}; + struct PointF { float x = 0.0f; float y = 0.0f; diff --git a/common/hal/common/session_data_defs.h b/common/hal/common/session_data_defs.h index 9510583..0adcbc2 100644 --- a/common/hal/common/session_data_defs.h +++ b/common/hal/common/session_data_defs.h @@ -42,6 +42,10 @@ namespace google_camera_hal { enum SessionDataKey : uint64_t { kSessionDataKeyInvalidKey = 0, // Add HAL-visible keys here (visible to GCH and HWL). + // A pointer to an int variable that indicates current + // Eis frame delay number. + // The pointer will be valid for the entire session. + kSessionDataKeyEisFrameDelayIntPtr, kSessionDataKeyBeginHwlKeys = 0xFFFFFFFF }; diff --git a/common/hal/common/vendor_tag_defs.h b/common/hal/common/vendor_tag_defs.h index d87ab63..7d93d8d 100644 --- a/common/hal/common/vendor_tag_defs.h +++ b/common/hal/common/vendor_tag_defs.h @@ -51,6 +51,23 @@ enum VendorTagIds : uint32_t { kEndMarker }; +enum class SmoothyMode : uint32_t { + // Stablizes frames while moves with user's intentional motion, e.g. panning. + // Similar to normal EIS. + kSteadyCamMode = 0, + + // Fixes the viewport as if videos are captured on a tripod. + kTripodMode, + + // Tracks an object of interest and keeps it at frame's salient position, e.g. + // center. + kTrackingMode, + + // Uses UW camera with a larger margin. In this way, we get a better video + // stabilization quality, while preserving a similar FoV as the main camera. + kSuperstabMode +}; + // Logical camera vendor tags static const std::vector<VendorTag> kLogicalCameraVendorTags = { // Logical camera default physical camera ID diff --git a/common/hal/google_camera_hal/camera_device.cc b/common/hal/google_camera_hal/camera_device.cc index f7d0535..e0c4e32 100644 --- a/common/hal/google_camera_hal/camera_device.cc +++ b/common/hal/google_camera_hal/camera_device.cc @@ -17,7 +17,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "GCH_CameraDevice" #define ATRACE_TAG ATRACE_TAG_CAMERA +#include <dlfcn.h> #include <log/log.h> +#include <sys/stat.h> #include <utils/Trace.h> #include "camera_device.h" @@ -26,6 +28,15 @@ namespace android { namespace google_camera_hal { +// HAL external capture session library path +#if defined(_LP64) +constexpr char kExternalCaptureSessionDir[] = + "/vendor/lib64/camera/capture_sessions/"; +#else // defined(_LP64) +constexpr char kExternalCaptureSessionDir[] = + "/vendor/lib/camera/capture_sessions/"; +#endif + std::unique_ptr<CameraDevice> CameraDevice::Create( std::unique_ptr<CameraDeviceHwl> camera_device_hwl, CameraBufferAllocatorHwl* camera_allocator_hwl) { @@ -63,6 +74,12 @@ status_t CameraDevice::Initialize( public_camera_id_ = camera_device_hwl->GetCameraId(); camera_device_hwl_ = std::move(camera_device_hwl); camera_allocator_hwl_ = camera_allocator_hwl; + status_t res = LoadExternalCaptureSession(); + if (res != OK) { + ALOGE("%s: Loading external capture sessions failed: %s(%d)", __FUNCTION__, + strerror(-res), res); + return res; + } return OK; } @@ -128,6 +145,7 @@ status_t CameraDevice::CreateCameraDeviceSession( } *session = CameraDeviceSession::Create(std::move(session_hwl), + external_session_factory_entries_, camera_allocator_hwl_); if (*session == nullptr) { ALOGE("%s: Creating a CameraDeviceSession failed: %s(%d)", __FUNCTION__, @@ -149,5 +167,74 @@ bool CameraDevice::IsStreamCombinationSupported( return supported; } +// Returns an array of regular files under dir_path. +static std::vector<std::string> FindLibraryPaths(const char* dir_path) { + std::vector<std::string> libs; + + errno = 0; + DIR* dir = opendir(dir_path); + if (!dir) { + ALOGD("%s: Unable to open directory %s (%s)", __FUNCTION__, dir_path, + strerror(errno)); + return libs; + } + + struct dirent* entry = nullptr; + while ((entry = readdir(dir)) != nullptr) { + std::string lib_path(dir_path); + lib_path += entry->d_name; + struct stat st; + if (stat(lib_path.c_str(), &st) == 0) { + if (S_ISREG(st.st_mode)) { + libs.push_back(lib_path); + } + } + } + + return libs; +} + +status_t CameraDevice::LoadExternalCaptureSession() { + ATRACE_CALL(); + + if (external_session_factory_entries_.size() > 0) { + ALOGI("%s: External capture session libraries already loaded; skip.", + __FUNCTION__); + return OK; + } + + for (const auto& lib_path : FindLibraryPaths(kExternalCaptureSessionDir)) { + ALOGI("%s: Loading %s", __FUNCTION__, lib_path.c_str()); + void* lib_handle = nullptr; + lib_handle = dlopen(lib_path.c_str(), RTLD_NOW); + if (lib_handle == nullptr) { + ALOGW("Failed loading %s.", lib_path.c_str()); + continue; + } + + GetCaptureSessionFactoryFunc external_session_factory_t = + reinterpret_cast<GetCaptureSessionFactoryFunc>( + dlsym(lib_handle, "GetCaptureSessionFactory")); + if (external_session_factory_t == nullptr) { + ALOGE("%s: dlsym failed (%s) when loading %s.", __FUNCTION__, + "GetCaptureSessionFactory", lib_path.c_str()); + dlclose(lib_handle); + lib_handle = nullptr; + continue; + } + + external_session_factory_entries_.push_back(external_session_factory_t); + external_capture_session_lib_handles_.push_back(lib_handle); + } + + return OK; +} + +CameraDevice::~CameraDevice() { + for (auto lib_handle : external_capture_session_lib_handles_) { + dlclose(lib_handle); + } +} + } // namespace google_camera_hal } // namespace android diff --git a/common/hal/google_camera_hal/camera_device.h b/common/hal/google_camera_hal/camera_device.h index 4cd1f6f..865bfa4 100644 --- a/common/hal/google_camera_hal/camera_device.h +++ b/common/hal/google_camera_hal/camera_device.h @@ -38,7 +38,7 @@ class CameraDevice { std::unique_ptr<CameraDeviceHwl> camera_device_hwl, CameraBufferAllocatorHwl* camera_allocator_hwl = nullptr); - virtual ~CameraDevice() = default; + virtual ~CameraDevice(); // Get the resource cost of this camera device. status_t GetResourceCost(CameraResourceCost* cost); @@ -79,6 +79,8 @@ class CameraDevice { // supported. stream_config contains the stream configurations. bool IsStreamCombinationSupported(const StreamConfiguration& stream_config); + status_t LoadExternalCaptureSession(); + protected: CameraDevice() = default; @@ -92,6 +94,10 @@ class CameraDevice { // hwl allocator CameraBufferAllocatorHwl* camera_allocator_hwl_ = nullptr; + + std::vector<GetCaptureSessionFactoryFunc> external_session_factory_entries_; + // Opened library handles that should be closed on destruction + std::vector<void*> external_capture_session_lib_handles_; }; } // namespace google_camera_hal diff --git a/common/hal/google_camera_hal/camera_device_session.cc b/common/hal/google_camera_hal/camera_device_session.cc index 421f233..7bdee63 100644 --- a/common/hal/google_camera_hal/camera_device_session.cc +++ b/common/hal/google_camera_hal/camera_device_session.cc @@ -19,10 +19,8 @@ #define ATRACE_TAG ATRACE_TAG_CAMERA #include "camera_device_session.h" -#include <dlfcn.h> #include <inttypes.h> #include <log/log.h> -#include <sys/stat.h> #include <utils/Trace.h> #include "basic_capture_session.h" @@ -53,17 +51,9 @@ std::vector<CaptureSessionEntryFuncs> BasicCaptureSession::IsStreamConfigurationSupported, .CreateSession = BasicCaptureSession::Create}}; -// HAL external capture session library path -#if defined(_LP64) -constexpr char kExternalCaptureSessionDir[] = - "/vendor/lib64/camera/capture_sessions/"; -#else // defined(_LP64) -constexpr char kExternalCaptureSessionDir[] = - "/vendor/lib/camera/capture_sessions/"; -#endif - std::unique_ptr<CameraDeviceSession> CameraDeviceSession::Create( std::unique_ptr<CameraDeviceSessionHwl> device_session_hwl, + std::vector<GetCaptureSessionFactoryFunc> external_session_factory_entries, CameraBufferAllocatorHwl* camera_allocator_hwl) { ATRACE_CALL(); if (device_session_hwl == nullptr) { @@ -83,7 +73,8 @@ std::unique_ptr<CameraDeviceSession> CameraDeviceSession::Create( } status_t res = - session->Initialize(std::move(device_session_hwl), camera_allocator_hwl); + session->Initialize(std::move(device_session_hwl), camera_allocator_hwl, + external_session_factory_entries); if (res != OK) { ALOGE("%s: Initializing CameraDeviceSession failed: %s (%d).", __FUNCTION__, strerror(-res), res); @@ -360,7 +351,8 @@ status_t CameraDeviceSession::InitializeBufferManagement( status_t CameraDeviceSession::Initialize( std::unique_ptr<CameraDeviceSessionHwl> device_session_hwl, - CameraBufferAllocatorHwl* camera_allocator_hwl) { + CameraBufferAllocatorHwl* camera_allocator_hwl, + std::vector<GetCaptureSessionFactoryFunc> external_session_factory_entries) { ATRACE_CALL(); if (device_session_hwl == nullptr) { ALOGE("%s: device_session_hwl cannot be nullptr.", __FUNCTION__); @@ -395,7 +387,7 @@ status_t CameraDeviceSession::Initialize( return res; } - res = LoadExternalCaptureSession(); + res = LoadExternalCaptureSession(external_session_factory_entries); if (res != OK) { ALOGE("%s: Loading external capture sessions failed: %s(%d)", __FUNCTION__, strerror(-res), res); @@ -467,34 +459,8 @@ void CameraDeviceSession::InitializeZoomRatioMapper( zoom_ratio_mapper_.Initialize(¶ms); } -// Returns an array of regular files under dir_path. -static std::vector<std::string> FindLibraryPaths(const char* dir_path) { - std::vector<std::string> libs; - - errno = 0; - DIR* dir = opendir(dir_path); - if (!dir) { - ALOGD("%s: Unable to open directory %s (%s)", __FUNCTION__, dir_path, - strerror(errno)); - return libs; - } - - struct dirent* entry = nullptr; - while ((entry = readdir(dir)) != nullptr) { - std::string lib_path(dir_path); - lib_path += entry->d_name; - struct stat st; - if (stat(lib_path.c_str(), &st) == 0) { - if (S_ISREG(st.st_mode)) { - libs.push_back(lib_path); - } - } - } - - return libs; -} - -status_t CameraDeviceSession::LoadExternalCaptureSession() { +status_t CameraDeviceSession::LoadExternalCaptureSession( + std::vector<GetCaptureSessionFactoryFunc> external_session_factory_entries) { ATRACE_CALL(); if (external_capture_session_entries_.size() > 0) { @@ -503,36 +469,16 @@ status_t CameraDeviceSession::LoadExternalCaptureSession() { return OK; } - for (const auto& lib_path : FindLibraryPaths(kExternalCaptureSessionDir)) { - ALOGI("%s: Loading %s", __FUNCTION__, lib_path.c_str()); - void* lib_handle = nullptr; - lib_handle = dlopen(lib_path.c_str(), RTLD_NOW); - if (lib_handle == nullptr) { - ALOGW("Failed loading %s.", lib_path.c_str()); - continue; - } - - GetCaptureSessionFactoryFunc external_session_factory_t = - reinterpret_cast<GetCaptureSessionFactoryFunc>( - dlsym(lib_handle, "GetCaptureSessionFactory")); - if (external_session_factory_t == nullptr) { - ALOGE("%s: dlsym failed (%s) when loading %s.", __FUNCTION__, - "GetCaptureSessionFactory", lib_path.c_str()); - dlclose(lib_handle); - lib_handle = nullptr; - continue; - } - + for (const auto& external_session_factory_t : + external_session_factory_entries) { ExternalCaptureSessionFactory* external_session = external_session_factory_t(); if (!external_session) { - ALOGE("%s: External session from (%s) may be incomplete", __FUNCTION__, - lib_path.c_str()); + ALOGE("%s: External session may be incomplete", __FUNCTION__); continue; } external_capture_session_entries_.push_back(external_session); - external_capture_session_lib_handles_.push_back(lib_handle); } return OK; @@ -548,10 +494,6 @@ CameraDeviceSession::~CameraDeviceSession() { delete external_session; } - for (auto lib_handle : external_capture_session_lib_handles_) { - dlclose(lib_handle); - } - if (buffer_mapper_v4_ != nullptr) { FreeImportedBufferHandles<android::hardware::graphics::mapper::V4_0::IMapper>( buffer_mapper_v4_); @@ -637,6 +579,28 @@ status_t CameraDeviceSession::ConfigureStreams( const StreamConfiguration& stream_config, std::vector<HalStream>* hal_config) { ATRACE_CALL(); + bool set_realtime_thread = false; + int32_t schedule_policy; + struct sched_param schedule_param = {0}; + if (utils::SupportRealtimeThread()) { + bool get_thread_schedule = false; + if (pthread_getschedparam(pthread_self(), &schedule_policy, + &schedule_param) == 0) { + get_thread_schedule = true; + } else { + ALOGE("%s: pthread_getschedparam fail", __FUNCTION__); + } + + if (get_thread_schedule) { + status_t res = utils::SetRealtimeThread(pthread_self()); + if (res != OK) { + ALOGE("%s: SetRealtimeThread fail", __FUNCTION__); + } else { + set_realtime_thread = true; + } + } + } + std::lock_guard<std::mutex> lock(session_lock_); std::lock_guard lock_capture_session(capture_session_lock_); @@ -687,6 +651,9 @@ status_t CameraDeviceSession::ConfigureStreams( if (capture_session_ == nullptr) { ALOGE("%s: Cannot find a capture session compatible with stream config", __FUNCTION__); + if (set_realtime_thread) { + utils::UpdateThreadSched(pthread_self(), schedule_policy, &schedule_param); + } return BAD_VALUE; } @@ -694,6 +661,10 @@ status_t CameraDeviceSession::ConfigureStreams( stream_buffer_cache_manager_ = StreamBufferCacheManager::Create(); if (stream_buffer_cache_manager_ == nullptr) { ALOGE("%s: Failed to create stream buffer cache manager.", __FUNCTION__); + if (set_realtime_thread) { + utils::UpdateThreadSched(pthread_self(), schedule_policy, + &schedule_param); + } return UNKNOWN_ERROR; } @@ -702,6 +673,10 @@ status_t CameraDeviceSession::ConfigureStreams( if (res != OK) { ALOGE("%s: Failed to register streams into stream buffer cache manager.", __FUNCTION__); + if (set_realtime_thread) { + utils::UpdateThreadSched(pthread_self(), schedule_policy, + &schedule_param); + } return res; } } @@ -722,6 +697,10 @@ status_t CameraDeviceSession::ConfigureStreams( pending_requests_tracker_ = PendingRequestsTracker::Create(*hal_config); if (pending_requests_tracker_ == nullptr) { ALOGE("%s: Cannot create a pending request tracker.", __FUNCTION__); + if (set_realtime_thread) { + utils::UpdateThreadSched(pthread_self(), schedule_policy, + &schedule_param); + } return UNKNOWN_ERROR; } @@ -740,6 +719,10 @@ status_t CameraDeviceSession::ConfigureStreams( last_request_settings_ = nullptr; last_timestamp_ns_for_trace_ = 0; + if (set_realtime_thread) { + utils::UpdateThreadSched(pthread_self(), schedule_policy, &schedule_param); + } + return OK; } @@ -1561,6 +1544,7 @@ status_t CameraDeviceSession::RegisterStreamsIntoCacheManagerLocked( [this, stream_id](uint32_t num_buffer, std::vector<StreamBuffer>* buffers, StreamBufferRequestError* status) -> status_t { + ATRACE_NAME("StreamBufferRequestFunc"); if (buffers == nullptr) { ALOGE("%s: buffers is nullptr.", __FUNCTION__); return BAD_VALUE; diff --git a/common/hal/google_camera_hal/camera_device_session.h b/common/hal/google_camera_hal/camera_device_session.h index aacc4d0..d373c40 100644 --- a/common/hal/google_camera_hal/camera_device_session.h +++ b/common/hal/google_camera_hal/camera_device_session.h @@ -97,6 +97,7 @@ class CameraDeviceSession { // lifetime of CameraDeviceSession static std::unique_ptr<CameraDeviceSession> Create( std::unique_ptr<CameraDeviceSessionHwl> device_session_hwl, + std::vector<GetCaptureSessionFactoryFunc> external_session_factory_entries, CameraBufferAllocatorHwl* camera_allocator_hwl = nullptr); virtual ~CameraDeviceSession(); @@ -154,8 +155,10 @@ class CameraDeviceSession { } }; - status_t Initialize(std::unique_ptr<CameraDeviceSessionHwl> device_session_hwl, - CameraBufferAllocatorHwl* camera_allocator_hwl); + status_t Initialize( + std::unique_ptr<CameraDeviceSessionHwl> device_session_hwl, + CameraBufferAllocatorHwl* camera_allocator_hwl, + std::vector<GetCaptureSessionFactoryFunc> external_session_factory_entries); // Initialize the latest available gralloc buffer mapper. status_t InitializeBufferMapper(); @@ -288,7 +291,8 @@ class CameraDeviceSession { void UnregisterThermalCallback(); // Load HAL external capture session libraries. - status_t LoadExternalCaptureSession(); + status_t LoadExternalCaptureSession( + std::vector<GetCaptureSessionFactoryFunc> external_session_factory_entries); void InitializeZoomRatioMapper(HalCameraMetadata* characteristics); diff --git a/common/hal/google_camera_hal/hal_utils.cc b/common/hal/google_camera_hal/hal_utils.cc index fb4e969..22635da 100644 --- a/common/hal/google_camera_hal/hal_utils.cc +++ b/common/hal/google_camera_hal/hal_utils.cc @@ -210,6 +210,24 @@ bool IsBayerCamera(const HalCameraMetadata* characteristics) { return false; } +bool IsFixedFocusCamera(const HalCameraMetadata* characteristics) { + if (characteristics == nullptr) { + ALOGE("%s: characteristics (%p) is nullptr", __FUNCTION__, characteristics); + return false; + } + + camera_metadata_ro_entry entry = {}; + status_t res = + characteristics->Get(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, &entry); + if (res != OK || entry.count != 1) { + ALOGE("%s: Getting ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE failed: %s(%d)", + __FUNCTION__, strerror(-res), res); + return false; + } + + return entry.data.f[0] == 0.0f; +} + bool IsRequestHdrplusCompatible(const CaptureRequest& request, int32_t preview_stream_id) { if (request.settings == nullptr) { diff --git a/common/hal/google_camera_hal/hal_utils.h b/common/hal/google_camera_hal/hal_utils.h index ec73805..1ae517d 100644 --- a/common/hal/google_camera_hal/hal_utils.h +++ b/common/hal/google_camera_hal/hal_utils.h @@ -67,6 +67,9 @@ bool IsBayerCamera(const HalCameraMetadata* characteristics); bool IsRequestHdrplusCompatible(const CaptureRequest& request, int32_t preview_stream_id); +// Return true if this is a fixed-focus camera. +bool IsFixedFocusCamera(const HalCameraMetadata* characteristics); + // Return if HDR+ stream is supported bool IsStreamHdrplusCompatible(const StreamConfiguration& stream_config, const HalCameraMetadata* characteristics); diff --git a/common/hal/hidl_service/hidl_camera_device_session.cc b/common/hal/hidl_service/hidl_camera_device_session.cc index 0b3aede..0179805 100644 --- a/common/hal/hidl_service/hidl_camera_device_session.cc +++ b/common/hal/hidl_service/hidl_camera_device_session.cc @@ -15,10 +15,13 @@ */ #define LOG_TAG "GCH_HidlCameraDeviceSession" +#define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 #include <log/log.h> #include <cutils/properties.h> +#include <cutils/trace.h> +#include <malloc.h> #include "hidl_camera_device_session.h" #include "hidl_profiler.h" @@ -68,6 +71,8 @@ std::unique_ptr<HidlCameraDeviceSession> HidlCameraDeviceSession::Create( HidlCameraDeviceSession::~HidlCameraDeviceSession() { close(); + // camera's closing, so flush any unused malloc pages + mallopt(M_PURGE, 0); } void HidlCameraDeviceSession::ProcessCaptureResult( @@ -661,7 +666,6 @@ Return<void> HidlCameraDeviceSession::close() { auto profiler_item = hidl_profiler::OnCameraClose(); device_session_ = nullptr; } - return Void(); } diff --git a/common/hal/hidl_service/hidl_camera_provider.cc b/common/hal/hidl_service/hidl_camera_provider.cc index a7ce5e2..7193a26 100644 --- a/common/hal/hidl_service/hidl_camera_provider.cc +++ b/common/hal/hidl_service/hidl_camera_provider.cc @@ -157,6 +157,8 @@ status_t HidlCameraProvider::Initialize() { }; google_camera_provider_->SetCallback(&camera_provider_callback_); + // purge pending malloc pages after initialization + mallopt(M_PURGE, 0); return OK; } diff --git a/common/hal/hidl_service/hidl_profiler.cc b/common/hal/hidl_service/hidl_profiler.cc index ff7b563..3c7e40d 100644 --- a/common/hal/hidl_service/hidl_profiler.cc +++ b/common/hal/hidl_service/hidl_profiler.cc @@ -36,13 +36,17 @@ struct HidlProfiler { mode |= google::camera_common::Profiler::SetPropFlag::kStopWatch; } profiler = google::camera_common::Profiler::Create(mode); - profiler->SetDumpFilePrefix( - "/data/vendor/camera/profiler/hidl_open_close_"); - profiler->Start("Overall", 0); + if (profiler != nullptr) { + profiler->SetDumpFilePrefix( + "/data/vendor/camera/profiler/hidl_open_close_"); + profiler->Start("Overall", 0); + } } ~HidlProfiler() { - profiler->End("Overall", 0); + if (profiler != nullptr) { + profiler->End("Overall", 0); + } } std::shared_ptr<google::camera_common::Profiler> profiler = nullptr; @@ -55,14 +59,15 @@ struct HidlProfiler { std::unique_ptr<HidlProfiler> gHidlProfiler = nullptr; void StartNewConnector() { - if (gHidlProfiler != nullptr) { + if (gHidlProfiler != nullptr && gHidlProfiler->profiler != nullptr) { gHidlProfiler->profiler->Start("<-- IDLE -->", ++gHidlProfiler->connector_counter); } } void EndConnector() { - if (gHidlProfiler != nullptr && gHidlProfiler->connector_counter != 0) { + if (gHidlProfiler != nullptr && gHidlProfiler->profiler != nullptr && + gHidlProfiler->connector_counter != 0) { gHidlProfiler->profiler->End("<-- IDLE -->", gHidlProfiler->connector_counter); } @@ -76,6 +81,11 @@ void EndProfiler() { std::unique_ptr<HidlProfilerItem> OnCameraOpen() { gHidlProfiler = std::make_unique<HidlProfiler>(); + if (gHidlProfiler == nullptr || gHidlProfiler->profiler == nullptr) { + ALOGE("%s: gHidlProfiler or profiler is nullptr.", __FUNCTION__); + return nullptr; + } + gHidlProfiler->has_camera_open = true; gHidlProfiler->profiler->SetUseCase("Open Camera"); @@ -88,6 +98,11 @@ std::unique_ptr<HidlProfilerItem> OnCameraFlush() { if (gHidlProfiler == nullptr) { gHidlProfiler = std::make_unique<HidlProfiler>(); } + + if (gHidlProfiler == nullptr || gHidlProfiler->profiler == nullptr) { + ALOGE("%s: gHidlProfiler or profiler is nullptr.", __FUNCTION__); + return nullptr; + } gHidlProfiler->profiler->SetUseCase("Flush Camera"); return std::make_unique<HidlProfilerItem>(gHidlProfiler->profiler, "Flush", StartNewConnector, @@ -99,6 +114,12 @@ std::unique_ptr<HidlProfilerItem> OnCameraClose() { if (gHidlProfiler == nullptr) { gHidlProfiler = std::make_unique<HidlProfiler>(); } + + if (gHidlProfiler == nullptr || gHidlProfiler->profiler == nullptr) { + ALOGE("%s: gHidlProfiler or profiler is nullptr.", __FUNCTION__); + return nullptr; + } + gHidlProfiler->profiler->SetUseCase("Close Camera"); return std::make_unique<HidlProfilerItem>(gHidlProfiler->profiler, "Close", EndProfiler); @@ -109,6 +130,12 @@ std::unique_ptr<HidlProfilerItem> OnCameraStreamConfigure() { if (gHidlProfiler == nullptr) { gHidlProfiler = std::make_unique<HidlProfiler>(); } + + if (gHidlProfiler == nullptr || gHidlProfiler->profiler == nullptr) { + ALOGE("%s: gHidlProfiler or profiler is nullptr.", __FUNCTION__); + return nullptr; + } + if (!gHidlProfiler->has_camera_open) { gHidlProfiler->profiler->SetUseCase("Reconfigure Stream"); } @@ -120,7 +147,7 @@ std::unique_ptr<HidlProfilerItem> OnCameraStreamConfigure() { void OnFirstFrameRequest() { EndConnector(); - if (gHidlProfiler != nullptr) { + if (gHidlProfiler != nullptr && gHidlProfiler->profiler != nullptr) { gHidlProfiler->profiler->Start( "First frame", google::camera_common::Profiler::kInvalidRequestId); gHidlProfiler->profiler->Start( @@ -129,7 +156,7 @@ void OnFirstFrameRequest() { } void OnFirstFrameResult() { - if (gHidlProfiler != nullptr) { + if (gHidlProfiler != nullptr && gHidlProfiler->profiler != nullptr) { gHidlProfiler->profiler->End( "First frame", google::camera_common::Profiler::kInvalidRequestId); gHidlProfiler->profiler->End( diff --git a/common/hal/hidl_service/hidl_utils.cc b/common/hal/hidl_service/hidl_utils.cc index 291fa3f..7967a43 100644 --- a/common/hal/hidl_service/hidl_utils.cc +++ b/common/hal/hidl_service/hidl_utils.cc @@ -128,8 +128,16 @@ Status ConvertToHidlStatus(status_t hal_status) { return Status::OK; case BAD_VALUE: return Status::ILLEGAL_ARGUMENT; + case -EBUSY: + return Status::CAMERA_IN_USE; + case -EUSERS: + return Status::MAX_CAMERAS_IN_USE; + case UNKNOWN_TRANSACTION: + return Status::METHOD_NOT_SUPPORTED; case INVALID_OPERATION: return Status::OPERATION_NOT_SUPPORTED; + case DEAD_OBJECT: + return Status::CAMERA_DISCONNECTED; default: return Status::INTERNAL_ERROR; } diff --git a/common/hal/hidl_service/hidl_utils.h b/common/hal/hidl_service/hidl_utils.h index 2116eed..72b0ac0 100644 --- a/common/hal/hidl_service/hidl_utils.h +++ b/common/hal/hidl_service/hidl_utils.h @@ -92,6 +92,11 @@ status_t ConverToHidlNotifyMessage( // Convert from HAL status_t to HIDL Status // OK is converted to Status::OK. // BAD_VALUE is converted to Status::ILLEGAL_ARGUMENT. +// -EBUSY is converted to Status::CAMERA_IN_USE. +// -EUSERS is converted to Status::MAX_CAMERAS_IN_USE. +// UNKNOWN_TRANSACTION is converted to Status::METHOD_NOT_SUPPORTED. +// INVALID_OPERATION is converted to Status::OPERATION_NOT_SUPPORTED. +// DEAD_OBJECT is converted to Status::CAMERA_DISCONNECTED. // All other errors are converted to Status::INTERNAL_ERROR. Status ConvertToHidlStatus(status_t hal_status); diff --git a/common/hal/hidl_service/service.cc b/common/hal/hidl_service/service.cc index 48217b7..2b203d7 100644 --- a/common/hal/hidl_service/service.cc +++ b/common/hal/hidl_service/service.cc @@ -23,6 +23,7 @@ #include <android/hardware/camera/provider/2.6/ICameraProvider.h> #include <binder/ProcessState.h> #include <hidl/LegacySupport.h> +#include <malloc.h> using android::hardware::defaultLazyPassthroughServiceImplementation; using android::hardware::defaultPassthroughServiceImplementation; @@ -38,6 +39,7 @@ int main() { ALOGI("Google camera provider service is starting."); // The camera HAL may communicate to other vendor components via // /dev/vndbinder + mallopt(M_DECAY_TIME, 1); android::ProcessState::initWithDriver("/dev/vndbinder"); int res; if (kLazyService) { diff --git a/common/hal/hwl_interface/zoom_ratio_mapper_hwl.h b/common/hal/hwl_interface/zoom_ratio_mapper_hwl.h index 019074c..edfc825 100644 --- a/common/hal/hwl_interface/zoom_ratio_mapper_hwl.h +++ b/common/hal/hwl_interface/zoom_ratio_mapper_hwl.h @@ -27,6 +27,9 @@ class ZoomRatioMapperHwl { public: virtual ~ZoomRatioMapperHwl() = default; + // Limit zoom ratio if concurrent mode is on + virtual void LimitZoomRatioIfConcurrent(float* zoom_ratio) const = 0; + // Apply zoom ratio to capture request virtual void UpdateCaptureRequest(CaptureRequest* request) = 0; diff --git a/common/hal/tests/camera_device_session_tests.cc b/common/hal/tests/camera_device_session_tests.cc index 926f4ad..823ece7 100644 --- a/common/hal/tests/camera_device_session_tests.cc +++ b/common/hal/tests/camera_device_session_tests.cc @@ -15,7 +15,9 @@ */ #define LOG_TAG "CameraDeviceSessionTests" +#include <dlfcn.h> #include <log/log.h> +#include <sys/stat.h> #include <gtest/gtest.h> @@ -33,9 +35,90 @@ using ::testing::_; using ::testing::AtLeast; using ::testing::Return; +// HAL external capture session library path +#if defined(_LP64) +constexpr char kExternalCaptureSessionDir[] = + "/vendor/lib64/camera/capture_sessions/"; +#else // defined(_LP64) +constexpr char kExternalCaptureSessionDir[] = + "/vendor/lib/camera/capture_sessions/"; +#endif + +// Returns an array of regular files under dir_path. +static std::vector<std::string> FindLibraryPaths(const char* dir_path) { + std::vector<std::string> libs; + + errno = 0; + DIR* dir = opendir(dir_path); + if (!dir) { + ALOGD("%s: Unable to open directory %s (%s)", __FUNCTION__, dir_path, + strerror(errno)); + return libs; + } + + struct dirent* entry = nullptr; + while ((entry = readdir(dir)) != nullptr) { + std::string lib_path(dir_path); + lib_path += entry->d_name; + struct stat st; + if (stat(lib_path.c_str(), &st) == 0) { + if (S_ISREG(st.st_mode)) { + libs.push_back(lib_path); + } + } + } + + return libs; +} + class CameraDeviceSessionTests : public ::testing::Test { protected: static constexpr uint32_t kCaptureTimeoutMs = 3000; + std::vector<GetCaptureSessionFactoryFunc> external_session_factory_entries_; + std::vector<void*> external_capture_session_lib_handles_; + + CameraDeviceSessionTests() { + LoadExternalCaptureSession(); + } + + ~CameraDeviceSessionTests() { + for (auto lib_handle : external_capture_session_lib_handles_) { + dlclose(lib_handle); + } + } + + status_t LoadExternalCaptureSession() { + if (external_session_factory_entries_.size() > 0) { + ALOGI("%s: External capture session libraries already loaded; skip.", + __FUNCTION__); + return OK; + } + + for (const auto& lib_path : FindLibraryPaths(kExternalCaptureSessionDir)) { + ALOGI("%s: Loading %s", __FUNCTION__, lib_path.c_str()); + void* lib_handle = nullptr; + lib_handle = dlopen(lib_path.c_str(), RTLD_NOW); + if (lib_handle == nullptr) { + ALOGW("Failed loading %s.", lib_path.c_str()); + continue; + } + + GetCaptureSessionFactoryFunc external_session_factory_t = + reinterpret_cast<GetCaptureSessionFactoryFunc>( + dlsym(lib_handle, "GetCaptureSessionFactory")); + if (external_session_factory_t == nullptr) { + ALOGE("%s: dlsym failed (%s) when loading %s.", __FUNCTION__, + "GetCaptureSessionFactory", lib_path.c_str()); + dlclose(lib_handle); + lib_handle = nullptr; + continue; + } + + external_session_factory_entries_.push_back(external_session_factory_t); + } + + return OK; + } void CreateMockSessionHwlAndCheck( std::unique_ptr<MockDeviceSessionHwl>* session_hwl) { @@ -49,7 +132,8 @@ class CameraDeviceSessionTests : public ::testing::Test { std::unique_ptr<CameraDeviceSession>* session) { ASSERT_NE(session, nullptr); - *session = CameraDeviceSession::Create(std::move(session_hwl)); + *session = CameraDeviceSession::Create(std::move(session_hwl), + external_session_factory_entries_); ASSERT_NE(*session, nullptr); } @@ -238,7 +322,8 @@ class CameraDeviceSessionTests : public ::testing::Test { }; TEST_F(CameraDeviceSessionTests, Create) { - auto session = CameraDeviceSession::Create(/*device_session_hwl=*/nullptr); + auto session = CameraDeviceSession::Create(/*device_session_hwl=*/nullptr, + external_session_factory_entries_); EXPECT_EQ(session, nullptr); uint32_t num_sessions = 5; diff --git a/common/hal/utils/result_dispatcher.cc b/common/hal/utils/result_dispatcher.cc index 2f89f4f..0dd6e33 100644 --- a/common/hal/utils/result_dispatcher.cc +++ b/common/hal/utils/result_dispatcher.cc @@ -23,6 +23,7 @@ #include <inttypes.h> #include "result_dispatcher.h" +#include "utils.h" namespace android { namespace google_camera_hal { @@ -50,6 +51,16 @@ ResultDispatcher::ResultDispatcher( ATRACE_CALL(); notify_callback_thread_ = std::thread([this] { this->NotifyCallbackThreadLoop(); }); + + if (utils::SupportRealtimeThread()) { + status_t res = + utils::SetRealtimeThread(notify_callback_thread_.native_handle()); + if (res != OK) { + ALOGE("%s: SetRealtimeThread fail", __FUNCTION__); + } else { + ALOGI("%s: SetRealtimeThread OK", __FUNCTION__); + } + } } ResultDispatcher::~ResultDispatcher() { diff --git a/common/hal/utils/stream_buffer_cache_manager.cc b/common/hal/utils/stream_buffer_cache_manager.cc index 2e25d1c..b801b9b 100644 --- a/common/hal/utils/stream_buffer_cache_manager.cc +++ b/common/hal/utils/stream_buffer_cache_manager.cc @@ -26,6 +26,7 @@ #include <chrono> #include "stream_buffer_cache_manager.h" +#include "utils.h" using namespace std::chrono_literals; @@ -43,6 +44,14 @@ static constexpr auto kBufferWaitingTimeOutSec = 400ms; StreamBufferCacheManager::StreamBufferCacheManager() { workload_thread_ = std::thread([this] { this->WorkloadThreadLoop(); }); + if (utils::SupportRealtimeThread()) { + status_t res = utils::SetRealtimeThread(workload_thread_.native_handle()); + if (res != OK) { + ALOGE("%s: SetRealtimeThread fail", __FUNCTION__); + } else { + ALOGI("%s: SetRealtimeThread OK", __FUNCTION__); + } + } } StreamBufferCacheManager::~StreamBufferCacheManager() { diff --git a/common/hal/utils/utils.cc b/common/hal/utils/utils.cc index 7c94454..24d0063 100644 --- a/common/hal/utils/utils.cc +++ b/common/hal/utils/utils.cc @@ -19,6 +19,7 @@ #include "utils.h" +#include <cutils/properties.h> #include <hardware/gralloc.h> #include "vendor_tag_defs.h" @@ -27,6 +28,8 @@ namespace android { namespace google_camera_hal { namespace utils { +const std::string kRealtimeThreadSetProp = "persist.camera.realtimethread"; + bool IsDepthStream(const Stream& stream) { if (stream.stream_type == StreamType::kOutput && stream.data_space == HAL_DATASPACE_DEPTH && @@ -380,6 +383,46 @@ void ConvertZoomRatio(const float zoom_ratio, } } +bool SupportRealtimeThread() { + static bool support_real_time = false; + static bool first_time = false; + if (first_time == false) { + first_time = true; + support_real_time = property_get_bool(kRealtimeThreadSetProp.c_str(), false); + } + + return support_real_time; +} + +status_t SetRealtimeThread(pthread_t thread) { + struct sched_param param = { + .sched_priority = 1, + }; + int32_t res = + pthread_setschedparam(thread, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m); + if (res != 0) { + ALOGE("%s: Couldn't set SCHED_FIFO", __FUNCTION__); + return BAD_VALUE; + } + + return OK; +} + +status_t UpdateThreadSched(pthread_t thread, int32_t policy, + struct sched_param* param) { + if (param == nullptr) { + ALOGE("%s: sched_param is nullptr", __FUNCTION__); + return BAD_VALUE; + } + int32_t res = pthread_setschedparam(thread, policy, param); + if (res != 0) { + ALOGE("%s: Couldn't set schedparam", __FUNCTION__); + return BAD_VALUE; + } + + return OK; +} + } // namespace utils } // namespace google_camera_hal } // namespace android diff --git a/common/hal/utils/utils.h b/common/hal/utils/utils.h index 27e0d8b..f79773f 100644 --- a/common/hal/utils/utils.h +++ b/common/hal/utils/utils.h @@ -66,6 +66,11 @@ bool IsHighSpeedModeFpsCompatible(StreamConfigurationMode mode, bool IsSessionParameterCompatible(const HalCameraMetadata* old_session, const HalCameraMetadata* new_session); +bool SupportRealtimeThread(); +status_t SetRealtimeThread(pthread_t thread); +status_t UpdateThreadSched(pthread_t thread, int32_t policy, + struct sched_param* param); + // Map the rectangle to the coordination of HAL. void ConvertZoomRatio(float zoom_ratio, const Dimension& active_array_dimension, int32_t* left, int32_t* top, int32_t* width, diff --git a/common/hal/utils/zoom_ratio_mapper.cc b/common/hal/utils/zoom_ratio_mapper.cc index a8f2f28..a05604e 100644 --- a/common/hal/utils/zoom_ratio_mapper.cc +++ b/common/hal/utils/zoom_ratio_mapper.cc @@ -16,9 +16,11 @@ #define LOG_TAG "GCH_ZoomRatioMapper" -#include "zoom_ratio_mapper.h" #include <log/log.h> +#include <cmath> + #include "utils.h" +#include "zoom_ratio_mapper.h" namespace android { namespace google_camera_hal { @@ -140,6 +142,14 @@ void ZoomRatioMapper::ApplyZoomRatio(const Dimension& active_array_dimension, zoom_ratio = zoom_ratio_range_.max; } + if (zoom_ratio_mapper_hwl_ != nullptr && is_request) { + zoom_ratio_mapper_hwl_->LimitZoomRatioIfConcurrent(&zoom_ratio); + } + + if (fabs(zoom_ratio - entry.data.f[0]) > 1e-9) { + metadata->Set(ANDROID_CONTROL_ZOOM_RATIO, &zoom_ratio, entry.count); + } + for (auto tag_id : kRectToConvert) { UpdateRects(zoom_ratio, tag_id, active_array_dimension, is_request, metadata); @@ -272,12 +282,12 @@ void ZoomRatioMapper::UpdatePoints(const float zoom_ratio, const uint32_t tag_id // x, y const uint32_t kDataSizePerPoint = 2; const uint32_t point_num = entry.count / kDataSizePerPoint; - std::vector<Point> points(point_num); + std::vector<PointI> points(point_num); uint32_t data_index = 0; for (uint32_t i = 0; i < point_num; i++) { data_index = i * kDataSizePerPoint; - Point* transformed = &points.at(i); + PointI* transformed = &points.at(i); transformed->x = entry.data.i32[data_index]; transformed->y = entry.data.i32[data_index + 1]; utils::RevertZoomRatio(zoom_ratio, active_array_dimension, true, diff --git a/common/hal/utils/zsl_buffer_manager.cc b/common/hal/utils/zsl_buffer_manager.cc index 9183476..22e1ee8 100644 --- a/common/hal/utils/zsl_buffer_manager.cc +++ b/common/hal/utils/zsl_buffer_manager.cc @@ -207,6 +207,12 @@ void ZslBufferManager::FreeUnusedBuffersLocked() { ATRACE_CALL(); if (empty_zsl_buffers_.size() <= kMaxUnusedBuffers || buffers_.size() <= buffer_descriptor_.immediate_num_buffers) { + idle_buffer_frame_counter_ = 0; + return; + } + + idle_buffer_frame_counter_++; + if (idle_buffer_frame_counter_ <= kMaxIdelBufferFrameCounter) { return; } diff --git a/common/hal/utils/zsl_buffer_manager.h b/common/hal/utils/zsl_buffer_manager.h index f43c8cc..5deb6eb 100644 --- a/common/hal/utils/zsl_buffer_manager.h +++ b/common/hal/utils/zsl_buffer_manager.h @@ -121,6 +121,11 @@ class ZslBufferManager { // kMaxUnusedBuffers, it will try to free excessive buffers. static const uint32_t kMaxUnusedBuffers = 2; + // Maximum number of frames with enough unused buffers. When the number of + // counter > kMaxIdelBufferFrameCounter, it will try to free excessive + // buffers. + static const uint32_t kMaxIdelBufferFrameCounter = 300; + const bool kMemoryProfilingEnabled; // Remove the oldest metadata. @@ -173,6 +178,9 @@ class ZslBufferManager { // Store the buffer descriptor when call AllocateBuffers() // Use it for AllocateExtraBuffers() HalBufferDescriptor buffer_descriptor_; + + // Count the number when there are enough unused buffers. + uint32_t idle_buffer_frame_counter_ = 0; }; } // namespace google_camera_hal diff --git a/common/profiler/profiler.cc b/common/profiler/profiler.cc index 2583b51..37f37f8 100644 --- a/common/profiler/profiler.cc +++ b/common/profiler/profiler.cc @@ -35,7 +35,9 @@ namespace { // Profiler implementatoin. class ProfilerImpl : public Profiler { public: - ProfilerImpl(SetPropFlag setting) : setting_(setting){}; + ProfilerImpl(SetPropFlag setting) : setting_(setting){ + object_init_time_ = CurrentTime(); + }; ~ProfilerImpl(); // Setup the name of use case the profiler is running. @@ -124,6 +126,9 @@ class ProfilerImpl : public Profiler { } } + // Timestamp of the class object initialized. + int64_t object_init_time_; + // Create folder if not exist. void CreateFolder(std::string folder_path); @@ -141,7 +146,8 @@ ProfilerImpl::~ProfilerImpl() { PrintResult(); } if (setting_ & SetPropFlag::kDumpBit) { - DumpResult(dump_file_prefix_ + use_case_ + ".txt"); + DumpResult(dump_file_prefix_ + use_case_ + "-TS" + + std::to_string(object_init_time_) + ".txt"); } } |