From ceceeafe8c344cd7a33a023df6c26a2e4ee6792c Mon Sep 17 00:00:00 2001 From: shukulk Date: Tue, 21 Apr 2026 22:16:01 +0530 Subject: [PATCH 1/4] le-camera-server : fix the out-of-bound ion_meta_fd access. - Recorder client accessed fds[1] unconditionally when service sent only 1 fd. - Non-gbm allocator always sends ion_meta_fd as -1 - fd received by ion_meta_fd is 1 due to out of bound case of fds_ vector. - During deletevideotrack this invalid ion_meta_fd was closed, which resulted in closing fd 1. In all linux processes by default fd 0, 1,2 are reserved for stdin,stdout,stderr respectively. Signed-off-by: Shubhankar Kulkarni Signed-off-by: Girish K --- recorder/src/client/qmmf_recorder_client.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/recorder/src/client/qmmf_recorder_client.cc b/recorder/src/client/qmmf_recorder_client.cc index d912b7a..47759d5 100644 --- a/recorder/src/client/qmmf_recorder_client.cc +++ b/recorder/src/client/qmmf_recorder_client.cc @@ -3683,13 +3683,8 @@ status_t RecorderServiceCallbackStub::ProcessCallbackMsg( std::vector buffers; for (auto &&b_data : data.buffers()) { BnBuffer buffer; - if (fds_.size()) { - buffer.ion_fd = fds_[0]; - buffer.ion_meta_fd = fds_[1]; - } else { - buffer.ion_fd = -1; - buffer.ion_meta_fd = -1; - } + buffer.ion_fd = (fds_.size() >= 1) ? fds_[0] : -1; + buffer.ion_meta_fd = (fds_.size() >= 2) ? fds_[1] : -1; buffer.img_id = b_data.img_id(); buffer.size = b_data.size(); buffer.timestamp = b_data.timestamp(); From f97eaa136496fbc8d9964bd5d5e199fd2307f67f Mon Sep 17 00:00:00 2001 From: Jai Shiv Date: Thu, 14 May 2026 16:17:03 +0530 Subject: [PATCH 2/4] cam-server: Set OCL_ICD_FILENAMES to Environment variable - In QLI 2.0 and mainline builds, multiple OpenCL implementations are present(ICD loader, Qualcomm Adreno, and Rusticl).The ICD loader selects vendor libraries in a non-deterministic order, causing inconsistent platform/device indexing. - Exporting: OCL_ICD_FILENAMES=/usr/lib/libOpenCL_adreno.so.1 forces the ICD loader to prioritize the Qualcomm OpenCL implementation,ensuring consistent behavior across builds. Removed LD_LIBRARY_PATH which is not used. - Note: Issue does not exist in QLI 1.0 (single vendor, hardcoded loading). Signed-off-by: Jai Shiv Signed-off-by: Girish K --- qmmf-server/cam-server-env | 2 +- qmmf-server/service/cam-server-base.service.in | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/qmmf-server/cam-server-env b/qmmf-server/cam-server-env index 4fbddb3..aa1328b 100644 --- a/qmmf-server/cam-server-env +++ b/qmmf-server/cam-server-env @@ -1 +1 @@ -LD_LIBRARY_PATH=/usr/lib/camera/components/:/usr/lib/camera/ +OCL_ICD_FILENAMES=/usr/lib/libOpenCL_adreno.so.1 diff --git a/qmmf-server/service/cam-server-base.service.in b/qmmf-server/service/cam-server-base.service.in index 4e2f9d0..4d31f75 100644 --- a/qmmf-server/service/cam-server-base.service.in +++ b/qmmf-server/service/cam-server-base.service.in @@ -43,6 +43,7 @@ RuntimeDirectory=cam_server RuntimeDirectoryMode=0775 CacheDirectory=camera ExecCondition=/usr/bin/check-camx-overlay.sh +EnvironmentFile=/etc/cam-server-env ExecStart=/usr/bin/cam-server [Install] From 40a09d6c7585f38297291eee14b0b9849eaddbc2 Mon Sep 17 00:00:00 2001 From: Jai Shiv Date: Tue, 21 Apr 2026 01:24:05 -0700 Subject: [PATCH 3/4] Revert^2 "cam-server: add support for offline camera" This reverts commit 9c483673f9d78e8cbe4084e4bf3c0803818f6359. Reason for revert: Signed-off-by: Girish K --- common/proto/qmmf.proto | 165 +++++++-------- config/common/CMakeLists.txt | 2 +- config/qcm6490/CMakeLists.txt | 4 + recorder/src/client/qmmf_recorder.cc | 6 +- recorder/src/client/qmmf_recorder_client.cc | 188 +++++++++++++++--- .../src/service/qmmf_offline_proc_impl.cc | 119 +++++------ recorder/src/service/qmmf_offline_proc_impl.h | 8 +- recorder/src/service/qmmf_recorder_impl.cc | 2 +- recorder/src/service/qmmf_recorder_service.cc | 168 +++++++++++++++- recorder/src/service/qmmf_recorder_service.h | 2 + 10 files changed, 473 insertions(+), 191 deletions(-) diff --git a/common/proto/qmmf.proto b/common/proto/qmmf.proto index e37b65b..aa223fc 100644 --- a/common/proto/qmmf.proto +++ b/common/proto/qmmf.proto @@ -124,53 +124,87 @@ enum ImageFormatMsg { IMAGE_FORMAT_BAYERRDI16BIT = 7; } -message ImageParamMsg { - ImageModeMsg mode = 1; - uint32 width = 2; - uint32 height = 3; - ImageFormatMsg format = 4; - uint32 quality = 5; - RotationMsg rotation = 6; +// Offline Camera +enum OfflinePostProcModeMsg { + OFFLINE_POSTPROC_YUV_TO_JPEG = 0; + OFFLINE_POSTPROC_YUV_TO_YUV = 1; + OFFLINE_POSTPROC_RAW_TO_YUV = 2; + OFFLINE_POSTPROC_RAW_TO_JPEG_SBS = 3; } -// TODO: Extra param related (check if required) -message ExtraParamMsg { - uint32 tag_id = 1; - uint32 entry_id = 2; - uint32 data_size = 3; +message OfflineCameraBufferParamsMsg { + uint32 width = 1; + uint32 height = 2; + VideoFormatMsg format = 3; } -// Offline JPEG -message OfflineJpegInputParamsMsg { - uint32 camera_id = 1; - uint32 width = 2; +message OfflineCameraInputParamsMsg { + repeated uint32 camera_id = 1; + uint32 width = 2; uint32 height = 3; } -message OfflineJpegOutputParamsMsg { +message OfflineCameraOutputParamsMsg { uint32 size = 1; } -message OfflineJpegBufferParamsMsg { - uint32 width = 1; - uint32 height = 2; - uint32 format = 3; +message OfflineCameraCreateParamsMsg { + repeated uint32 camera_id = 1; + OfflineCameraBufferParamsMsg in_buffer = 2; + OfflineCameraBufferParamsMsg out_buffer = 3; + OfflinePostProcModeMsg process_mode = 4; + repeated uint32 metadata_step = 5; + repeated bytes request_metadata_path = 6; + repeated bytes session_meta = 7; } -message OfflineJpegCreateParamsMsg { - uint32 process_mode = 1; - OfflineJpegBufferParamsMsg in_buffer = 2; - OfflineJpegBufferParamsMsg out_buffer = 3; +message OfflineCameraProcessParamsMsg { + repeated int32 in_buf_fd = 1; + int32 out_buf_fd = 2; + bytes meta = 3; } -message OfflineJpegMetaMsg { - uint32 quality = 1; +message GetOfflineCameraParamsReqMsg { + uint32 client_id = 1; + OfflineCameraInputParamsMsg in_params = 2; } -message OfflineJpegProcessParamsMsg { - int32 in_buf_fd = 1; - int32 out_buf_fd = 2; - OfflineJpegMetaMsg metadata = 3; +message GetOfflineCameraParamsRespMsg { + uint32 status = 1; + OfflineCameraOutputParamsMsg out_params = 2; +} + +// Create offline camera post-processing context +message CreateOfflineCameraReqMsg { + uint32 client_id = 1; + OfflineCameraCreateParamsMsg params = 2; +} + +// Run offline camera processing +message ProcessOfflineCameraReqMsg { + uint32 client_id = 1; + OfflineCameraProcessParamsMsg process_params = 2; +} + +// Destroy offline camera post-processing context +message DestroyOfflineCameraReqMsg { + uint32 client_id = 1; +} + +message ImageParamMsg { + ImageModeMsg mode = 1; + uint32 width = 2; + uint32 height = 3; + ImageFormatMsg format = 4; + uint32 quality = 5; + RotationMsg rotation = 6; +} + +// TODO: Extra param related (check if required) +message ExtraParamMsg { + uint32 tag_id = 1; + uint32 entry_id = 2; + uint32 data_size = 3; } message ConnectRespMsg { @@ -371,32 +405,6 @@ message GetVendorTagDescriptorRespMsg { bytes descs = 2; } -// GetOfflineJPEGParams -message GetOfflineJPEGParamsReqMsg { - uint32 client_id = 1; - OfflineJpegInputParamsMsg in_params = 2; - OfflineJpegOutputParamsMsg out_params = 3; -} - -// CreateOfflineJPEG -message CreateOfflineJPEGReqMsg { - uint32 client_id = 1; - OfflineJpegCreateParamsMsg params = 2; -} - -// EncodeOfflineJPEG -message EncodeOfflineJPEGReqMsg { - uint32 client_id = 1; - BufferInfoMsg in_buf = 2; - BufferInfoMsg out_buf = 3; - OfflineJpegMetaMsg meta = 4; -} - -// DestroyOfflineJPEG -message DestroyOfflineJPEGReqMsg { - uint32 client_id = 1; -} - // Client to Server API messages enum RECORDER_SERVICE_CMDS { RECORDER_UNKNOWN = 0; @@ -421,13 +429,13 @@ enum RECORDER_SERVICE_CMDS { RECORDER_GET_DEFAULT_CAPTURE_PARAMS = 19; RECORDER_GET_CAMERA_CHARACTERISTICS = 20; RECORDER_GET_VENDOR_TAG_DESCRIPTOR = 21; - RECORDER_CONFIGURE_OFFLINE_JPEG = 22; - RECORDER_ENCODE_OFFLINE_JPEG = 23; - RECORDER_DESTROY_OFFLINE_JPEG = 24; - RECORDER_CALLBACK_SOCKET_READY = 25; - RECORDER_GET_CAMERA_STATIC_INFO = 26; - RECORDER_GET_SUPPORTED_INTERFACE_VER = 27; - RECORDER_GET_OFFLINE_PARAMS = 28; + RECORDER_CALLBACK_SOCKET_READY = 22; + RECORDER_GET_CAMERA_STATIC_INFO = 23; + RECORDER_GET_SUPPORTED_INTERFACE_VER = 24; + RECORDER_GET_OFFLINE_CAMERA_PARAMS = 25; + RECORDER_CREATE_OFFLINE_CAMERA = 26; + RECORDER_PROCESS_OFFLINE_CAMERA = 27; + RECORDER_DESTROY_OFFLINE_CAMERA = 28; RECORDER_DYNAMIC_CAPTURE_IMAGE = 29; } @@ -453,13 +461,13 @@ message RecorderClientReqMsg { SetVHDRReqMsg set_vhdr = 18; GetDefaultCaptureParamReqMsg get_default_capture_param = 19; GetCameraCharacteristicsReqMsg get_camera_characteristics = 20; - CreateOfflineJPEGReqMsg create_offline_jpeg = 21; - EncodeOfflineJPEGReqMsg encode_offline_jpeg = 22; - DestroyOfflineJPEGReqMsg destroy_offline_jpeg = 23; - CallbackSocketReadyMsg callback_socket_ready = 24; - DummyMsg dummy_msg = 25; - GetCamStaticInfoReqMsg get_cam_static_info = 26; - GetOfflineJPEGParamsReqMsg get_offline_jpeg_params = 27; + CallbackSocketReadyMsg callback_socket_ready = 21; + DummyMsg dummy_msg = 22; + GetCamStaticInfoReqMsg get_cam_static_info = 23; + GetOfflineCameraParamsReqMsg get_offline_camera_params = 24; + CreateOfflineCameraReqMsg create_offline_camera = 25; + ProcessOfflineCameraReqMsg process_offline_camera = 26; + DestroyOfflineCameraReqMsg destroy_offline_camera = 27; DynamicCaptureImageReqMsg dynamic_capture_image = 28; } } @@ -476,6 +484,7 @@ message RecorderClientRespMsg { DummyMsg dummy_msg = 8; GetCamStaticInfoRespMsg get_cam_static_info_resp = 9; GetSupportedInterfaceVerRespMsg get_supported_interface_ver_resp = 10; + GetOfflineCameraParamsRespMsg get_offline_camera_params_resp = 11; } } @@ -483,7 +492,7 @@ message RecorderClientRespMsg { enum RECORDER_SERVICE_CB_CMDS { RECORDER_NOTIFY_EVENT= 0; RECORDER_NOTIFY_SNAPSHOT_DATA= 1; - RECORDER_NOTIFY_OFFLINE_JPEG_DATA= 2; + RECORDER_NOTIFY_OFFLINE_CAMERA_DATA = 2; RECORDER_NOTIFY_VIDEO_TRACK_DATA= 3; RECORDER_NOTIFY_VIDEO_TRACK_EVENT= 4; RECORDER_NOTIFY_CAMERA_RESULT= 5; @@ -501,11 +510,6 @@ message NotifySnapshotDataMsg { BufferMetaMsg meta = 4; } -message NotifyOfflineJpegDataMsg { - int32 buf_fd = 1; - uint32 encoded_size = 2; -} - message NotifyVideoTrackDataMsg { uint32 track_id = 1; repeated BufferInfoMsg buffers = 2; @@ -523,12 +527,17 @@ message NotifyCameraResultMsg { bytes result_meta = 2; } +message NotifyOfflineCameraDataMsg { + int32 buf_fd = 1; + uint32 encoded_size = 2; +} + message RecorderClientCallbacksAsync { RECORDER_SERVICE_CB_CMDS cmd = 1; oneof callback { NotifyRecorderEventMsg recorder_event = 2; NotifySnapshotDataMsg snapshot_data = 3; - NotifyOfflineJpegDataMsg offline_jpeg_data = 4; + NotifyOfflineCameraDataMsg offline_camera_data = 4; NotifyVideoTrackDataMsg video_track_data = 5; NotifyVideoTrackEventMsg video_track_event = 6; NotifyCameraResultMsg camera_result = 7; diff --git a/config/common/CMakeLists.txt b/config/common/CMakeLists.txt index a8466b8..52e2c7f 100644 --- a/config/common/CMakeLists.txt +++ b/config/common/CMakeLists.txt @@ -22,7 +22,7 @@ set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -DUSE_FPS_IDX") set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -DDISABLE_RESCALER_COLORSPACE") -set(JPEG_LIB camera/components/com.qti.offline.jpeg.so.0) +set(JPEG_LIB chiofflinepostproclib.so.0) set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -DJPEG_POSTPROC_LIB=\"\\\"${JPEG_LIB}\\\"\"") diff --git a/config/qcm6490/CMakeLists.txt b/config/qcm6490/CMakeLists.txt index 1ede293..b400beb 100644 --- a/config/qcm6490/CMakeLists.txt +++ b/config/qcm6490/CMakeLists.txt @@ -2,4 +2,8 @@ project(config-qcm6490) set(PLATFORM_CXX_FLAGS "${PLATFORM_CXX_FLAGS} -DCAMERA_HAL_API_VERSION=0x0306") +set(PLATFORM_CXX_FLAGS "${PLATFORM_CXX_FLAGS} -DENABLE_OFFLINE_JPEG") + +set(ENABLE_OFFLINE_JPEG "1" PARENT_SCOPE) + set(PLATFORM_CXX_FLAGS ${PLATFORM_CXX_FLAGS} PARENT_SCOPE) diff --git a/recorder/src/client/qmmf_recorder.cc b/recorder/src/client/qmmf_recorder.cc index b0f1f95..6b6d55c 100644 --- a/recorder/src/client/qmmf_recorder.cc +++ b/recorder/src/client/qmmf_recorder.cc @@ -369,8 +369,8 @@ status_t Recorder::GetOfflineJpegParams(const OfflineJpegInputParams &in_params, OfflineJpegOutputParams &out_params) { QMMF_INFO("%s: Enter" ,__func__); assert(recorder_client_ != NULL); - OfflineCameraInputParams offline_in_params; - OfflineCameraOutputParams offline_out_params; + OfflineCameraInputParams offline_in_params{}; + OfflineCameraOutputParams offline_out_params{}; offline_in_params.camera_id[0] = in_params.camera_id; offline_in_params.width = in_params.width; @@ -394,7 +394,7 @@ status_t Recorder::CreateOfflineJPEG( QMMF_DEBUG("%s: Enter" ,__func__); assert(recorder_client_ != NULL); - OfflineCameraCreateParams offline_params; + OfflineCameraCreateParams offline_params{}; offline_params.process_mode = params.process_mode; offline_params.camera_id[0] = params.camera_id; offline_params.in_buffer.width = params.in_buffer.width; diff --git a/recorder/src/client/qmmf_recorder_client.cc b/recorder/src/client/qmmf_recorder_client.cc index 47759d5..346d5a9 100644 --- a/recorder/src/client/qmmf_recorder_client.cc +++ b/recorder/src/client/qmmf_recorder_client.cc @@ -883,35 +883,153 @@ class RecorderServiceProxy: public IRecorderService { status_t GetOfflineParams(const uint32_t client_id, const OfflineCameraInputParams &in_params, OfflineCameraOutputParams &out_params) { - // To be implemented - return -EPERM; + RecorderClientReqMsg cmd; + cmd.set_command(RECORDER_SERVICE_CMDS::RECORDER_GET_OFFLINE_CAMERA_PARAMS); + + auto *req = cmd.mutable_get_offline_camera_params(); + req->set_client_id(client_id); + + auto *in = req->mutable_in_params(); + + for (auto id : in_params.camera_id) { + in->add_camera_id(id); + } + + in->set_width(in_params.width); + in->set_height(in_params.height); + + status_t ret = SendRequest(cmd); + if (ret < 0) return ret; + + RecorderClientRespMsg resp; + ret = RecvResponse(resp); + if (ret < 0) return ret; + + ret = resp.status(); + if (ret != 0) return ret; + + const auto &out_msg = resp.get_offline_camera_params_resp().out_params(); + out_params.size = out_msg.size(); + + return 0; } status_t CreateOfflineProcess(const uint32_t client_id, - const OfflineCameraCreateParams& params) { - // To be implemented - return -EPERM; + const OfflineCameraCreateParams ¶ms) { + RecorderClientReqMsg cmd; + cmd.set_command(RECORDER_SERVICE_CMDS::RECORDER_CREATE_OFFLINE_CAMERA); + + auto *req = cmd.mutable_create_offline_camera(); + req->set_client_id(client_id); + + auto *p = req->mutable_params(); + + for (auto id : params.camera_id) { + p->add_camera_id(id); + } + + auto *in_buf = p->mutable_in_buffer(); + in_buf->set_width(params.in_buffer.width); + in_buf->set_height(params.in_buffer.height); + in_buf->set_format(static_cast(params.in_buffer.format)); + + auto *out_buf = p->mutable_out_buffer(); + out_buf->set_width(params.out_buffer.width); + out_buf->set_height(params.out_buffer.height); + out_buf->set_format(static_cast(params.out_buffer.format)); + + p->set_process_mode( + static_cast(params.process_mode)); + + status_t ret = SendRequest(cmd); + if (ret < 0) return ret; + + RecorderClientRespMsg resp; + ret = RecvResponse(resp); + if (ret < 0) return ret; + + return resp.status(); } - status_t ProcOfflineProcess(const uint32_t client_id, - const BnBuffer& in_buf0, - const BnBuffer& in_buf1, - const BnBuffer& out_buf, - const CameraMetadata& meta) { - // To be implemented - return -EPERM; + status_t ProcOfflineProcess(const uint32_t client_id, const BnBuffer &in_buf0, + const BnBuffer &in_buf1, const BnBuffer &out_buf, + const CameraMetadata &meta) { + RecorderClientReqMsg cmd; + cmd.set_command(RECORDER_SERVICE_CMDS::RECORDER_PROCESS_OFFLINE_CAMERA); + + auto *req = cmd.mutable_process_offline_camera(); + req->set_client_id(client_id); + + auto *p = req->mutable_process_params(); + p->add_in_buf_fd(in_buf0.buffer_id); + p->add_in_buf_fd(in_buf1.buffer_id); + p->set_out_buf_fd(out_buf.buffer_id); + + const camera_metadata_t *meta_buffer = meta.getAndLock(); + if (!meta_buffer) { + QMMF_ERROR("%s: meta.getAndLock() returned null", __func__); + return -EINVAL; + } + + const uint32_t compact_size = + CameraMetadata::get_camera_metadata_compact_size(meta_buffer); + if (compact_size == 0) { + p->mutable_meta()->clear(); + } else { + std::string *bytes = p->mutable_meta(); + bytes->resize(compact_size); + void *copied = CameraMetadata::copy_camera_metadata( + &(*bytes)[0], compact_size, meta_buffer); + if (!copied) { + const_cast(meta).unlock(meta_buffer); + QMMF_ERROR("%s: Failed to copy frame metadata (size=%u)", __func__, + compact_size); + return -EINVAL; + } + } + const_cast(meta).unlock(meta_buffer); + + std::vector fds; + fds.push_back(in_buf0.buffer_id); + fds.push_back(out_buf.buffer_id); + + status_t ret = SendRequest(cmd, fds); + if (ret < 0) return ret; + + RecorderClientRespMsg resp; + ret = RecvResponse(resp); + if (ret < 0) return ret; + + return static_cast(resp.status()); } status_t DestroyOfflineProcess(const uint32_t client_id) { - // To be implemented - return -EPERM; + RecorderClientReqMsg cmd; + cmd.set_command(RECORDER_SERVICE_CMDS::RECORDER_DESTROY_OFFLINE_CAMERA); + + auto *req = cmd.mutable_destroy_offline_camera(); + req->set_client_id(client_id); + + status_t ret = SendRequest(cmd); + if (ret < 0) return ret; + + RecorderClientRespMsg resp; + ret = RecvResponse(resp); + if (ret < 0) return ret; + + return resp.status(); } + private: - status_t SendRequest(RecorderClientReqMsg &cmd) { + status_t SendRequest(RecorderClientReqMsg &cmd, + const std::vector &fds = {}) { uint8_t offset = 4; auto msg_size = cmd.ByteSizeLong(); auto buf_size = msg_size + offset; void *buffer = malloc(buf_size); + struct cmsghdr *cmsg = NULL; + struct msghdr msg = {0}; + struct iovec io; if (!buffer) { QMMF_DEBUG("%s: Memory Allocation failed!", __func__); @@ -921,16 +1039,33 @@ class RecorderServiceProxy: public IRecorderService { *(static_cast(buffer)) = msg_size; cmd.SerializeToArray(static_cast(buffer) + offset, msg_size); - ssize_t bytes_sent = send(socket_, buffer, buf_size, 0); - free (buffer); + io.iov_base = buffer; + io.iov_len = buf_size; + msg.msg_iov = &io; + msg.msg_iovlen = 1; + + char cmsgbuf[CMSG_SPACE(fds.size() * sizeof(int32_t))] = {0}; + if (!fds.empty()) { + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(fds.size() * sizeof(int32_t)); + memmove(CMSG_DATA(cmsg), fds.data(), fds.size() * sizeof(int32_t)); + } + + ssize_t bytes_sent = sendmsg(socket_, (struct msghdr *)&msg, 0); + free(buffer); if (bytes_sent == -1) { return -errno; } - QMMF_DEBUG("%s: Sent to server cmd: %u, buf_size:%ld, bytes:%ld", - __func__, cmd.command(), buf_size, bytes_sent); + QMMF_DEBUG("%s: Sent to server cmd: %u, buf_size:%ld, bytes:%ld", __func__, + cmd.command(), buf_size, bytes_sent); return 0; } + status_t RecvResponse(RecorderClientRespMsg &resp) { char buffer[kMaxSocketBufSize] = {0}; uint32_t msg_sz = 0; @@ -970,6 +1105,7 @@ class RecorderServiceProxy: public IRecorderService { return 0; } + std::shared_ptr service_cb_handler_; int socket_; std::mutex socket_lock_; @@ -3673,10 +3809,6 @@ status_t RecorderServiceCallbackStub::ProcessCallbackMsg( return 0; } break; - case RECORDER_SERVICE_CB_CMDS::RECORDER_NOTIFY_OFFLINE_JPEG_DATA: { - return 0; - } - break; case RECORDER_SERVICE_CB_CMDS::RECORDER_NOTIFY_VIDEO_TRACK_DATA: { NotifyVideoTrackDataMsg data = msg.video_track_data(); uint32_t track_id = data.track_id(); @@ -3718,7 +3850,15 @@ status_t RecorderServiceCallbackStub::ProcessCallbackMsg( } break; case RECORDER_SERVICE_CB_CMDS::RECORDER_NOTIFY_VIDEO_TRACK_EVENT: { - //TODO: + return 0; + } + case RECORDER_SERVICE_CB_CMDS::RECORDER_NOTIFY_OFFLINE_CAMERA_DATA: { + NotifyOfflineCameraDataMsg data = msg.offline_camera_data(); + + int32_t buf_fd = data.buf_fd(); + uint32_t out_size = data.encoded_size(); + + NotifyOfflineProcData(buf_fd, out_size); return 0; } break; diff --git a/recorder/src/service/qmmf_offline_proc_impl.cc b/recorder/src/service/qmmf_offline_proc_impl.cc index 055fa43..5727caa 100644 --- a/recorder/src/service/qmmf_offline_proc_impl.cc +++ b/recorder/src/service/qmmf_offline_proc_impl.cc @@ -8,7 +8,9 @@ #include "qmmf_offline_proc_impl.h" #include -#include + +#include +#include #include "common/utils/qmmf_log.h" #ifdef QCAMERA3_TAG_LOCAL_COPY @@ -45,7 +47,7 @@ status_t OfflineProcess::Init( assert(remote_cb_handle != nullptr); remote_cb_handle_ = remote_cb_handle; - int32_t ret = NO_ERROR; + int32_t ret = 0; // This is required for proper working of the jpeg lib ret = CameraModule::getInstance(&camera_module_); @@ -58,7 +60,7 @@ status_t OfflineProcess::Init( if (!offline_proc_lib_) { QMMF_ERROR("%s: No postproc lib, dlopen failed with: %s.", __func__, dlerror()); - return BAD_VALUE; + return -EINVAL; } pCameraPostProcCreate = (PFN_CameraPostProc_Create) @@ -79,7 +81,7 @@ status_t OfflineProcess::Init( pCameraPostProcProcess, pCameraPostProcDestroy, pCameraPostProcRelease); - return BAD_VALUE; + return -EINVAL; } QMMF_INFO("%s: Exit ", __func__); @@ -117,7 +119,7 @@ status_t OfflineProcess::DeInit() { } QMMF_INFO("%s: Exit ", __func__); - return NO_ERROR; + return 0; } status_t OfflineProcess::RegisterClient(const uint32_t client_id) { @@ -126,7 +128,7 @@ status_t OfflineProcess::RegisterClient(const uint32_t client_id) { std::lock_guard client_lock(client_pproc_lock_); if (IsClientFound(client_id)) { QMMF_INFO("%s: Client %d already registered.", __func__, client_id); - return ALREADY_EXISTS; + return -EEXIST; } clients_list_.push_back(client_id); @@ -134,7 +136,7 @@ status_t OfflineProcess::RegisterClient(const uint32_t client_id) { QMMF_INFO("%s: Exit client_id %d", __func__, client_id); - return NO_ERROR; + return 0; } status_t OfflineProcess::DeRegisterClient(const uint32_t client_id) { @@ -143,7 +145,7 @@ status_t OfflineProcess::DeRegisterClient(const uint32_t client_id) { std::lock_guard client_lock(client_pproc_lock_); if (!IsClientFound(client_id)) { QMMF_ERROR("%s: Client %d not found.", __func__, client_id); - return BAD_VALUE; + return -EINVAL; } for (uint32_t i = 0; i < clients_list_.size(); i++) { @@ -156,7 +158,7 @@ status_t OfflineProcess::DeRegisterClient(const uint32_t client_id) { QMMF_INFO("%s: Exit client_id %d", __func__, client_id); - return NO_ERROR; + return 0; } bool OfflineProcess::IsClientFound(const uint32_t& client_id) { @@ -228,7 +230,7 @@ status_t OfflineProcess::GetParams(const uint32_t client_id, if (ret > 0) { out_params.size = ret; QMMF_DEBUG("%s calculate blob size is %d", __func__, ret); - ret = NO_ERROR; + ret = 0; } QMMF_INFO("%s: Enter client_id %d", __func__, client_id); @@ -251,7 +253,7 @@ status_t OfflineProcess::Create(const uint32_t client_id, if(!IsClientFound(client_id)) { QMMF_ERROR("%s Error: Client %d not found.", __func__, client_id); - return BAD_VALUE; + return -EINVAL; } OfflineCreateParams create_params; @@ -279,12 +281,12 @@ status_t OfflineProcess::Create(const uint32_t client_id, GetUsageFromFormat(buffer_format); #endif - create_params.config.clientCb = OfflineCb; + create_params.config.pResultCallBack = OfflineCb; create_params.cb_data = new OfflineCbData; create_params.cb_data->offline_proc = this; create_params.cb_data->client_id = client_id; - create_params.config.clientData = + create_params.config.pClientData = reinterpret_cast(create_params.cb_data); #ifdef FEATURE_OFFLINE_IPE_ENABLE @@ -309,13 +311,13 @@ status_t OfflineProcess::Create(const uint32_t client_id, (create_params.config.processMode == RAWToJPEGSBS)) && (!offlineipe_enable)) { QMMF_INFO("%s offline IPE module not support.", __func__); - return BAD_VALUE; + return -EINVAL; } create_params.pproc_instance = pCameraPostProcCreate(&create_params.config); if (!create_params.pproc_instance) { QMMF_ERROR("%s pproc_instance creation failed.", __func__); - return BAD_VALUE; + return -EINVAL; } { @@ -331,7 +333,7 @@ status_t OfflineProcess::Create(const uint32_t client_id, client_requests_map_.emplace(client_id, OfflineRequests()); QMMF_INFO("%s: Exit client_id %d", __func__, client_id); - return NO_ERROR; + return 0; } status_t OfflineProcess::Process(const uint32_t client_id, @@ -344,7 +346,7 @@ status_t OfflineProcess::Process(const uint32_t client_id, std::unique_lock client_lock(client_pproc_lock_); if(!IsClientFound(client_id)) { QMMF_ERROR("%s Error: Client %d not found.", __func__, client_id); - return BAD_VALUE; + return -EINVAL; } native_handle_t *input_nh0; @@ -357,54 +359,29 @@ status_t OfflineProcess::Process(const uint32_t client_id, input_nh1 = native_handle_create(2, 8); output_nh = native_handle_create(2, 8); - //check if buf fd is present { std::lock_guard l(client_fd_lock_); - if (-1 != in_buf0.ion_fd) { - if (0 == client_fd_map_[client_id].count(in_buf0.buffer_id)) { - client_fd_map_[client_id].emplace(in_buf0.buffer_id, in_buf0.ion_fd); - } else { - QMMF_ERROR("%s: Error: Expected buf fd %d, but got %d for buf id (%d)", - __func__, - client_fd_map_[client_id].at(in_buf0.buffer_id), - in_buf0.ion_fd, - in_buf0.buffer_id); - native_handle_delete(input_nh0); - native_handle_delete(input_nh1); - native_handle_delete(output_nh); - return BAD_VALUE; - } - } - if (-1 != in_buf1.ion_fd) { - if (0 == client_fd_map_[client_id].count(in_buf1.buffer_id)) { - client_fd_map_[client_id].emplace(in_buf1.buffer_id, in_buf1.ion_fd); - } else { - QMMF_ERROR("%s: Error: Expected buf fd %d, but got %d for buf id (%d)", - __func__, - client_fd_map_[client_id].at(in_buf1.buffer_id), - in_buf1.ion_fd, - in_buf1.buffer_id); - native_handle_delete(input_nh0); - native_handle_delete(input_nh1); - native_handle_delete(output_nh); - return BAD_VALUE; - } - } - if (-1 != out_buf.ion_fd) { - if (0 == client_fd_map_[client_id].count(out_buf.buffer_id)) { - client_fd_map_[client_id].emplace(out_buf.buffer_id, out_buf.ion_fd); + auto& fd_map = client_fd_map_[client_id]; + + auto update_fd = [&](int32_t buffer_id, int32_t new_fd) { + if (new_fd == -1 || buffer_id == -1) + return; + + auto it = fd_map.find(buffer_id); + if (it == fd_map.end()) { + fd_map.emplace(buffer_id, new_fd); } else { - QMMF_ERROR("%s: Error: Expected buf fd %d, but got %d for buf id (%d)", - __func__, - client_fd_map_[client_id].at(out_buf.buffer_id), - out_buf.ion_fd, - out_buf.buffer_id); - native_handle_delete(input_nh0); - native_handle_delete(input_nh1); - native_handle_delete(output_nh); - return BAD_VALUE; + int32_t old_fd = it->second; + if (old_fd != new_fd && old_fd >= 0) { + close(old_fd); + } + it->second = new_fd; } - } + }; + + update_fd(in_buf0.buffer_id, in_buf0.ion_fd); + update_fd(in_buf1.buffer_id, in_buf1.ion_fd); + update_fd(out_buf.buffer_id, out_buf.ion_fd); } PostProcHandleParams in_handle_params0, in_handle_params1, out_handle_params; @@ -427,7 +404,7 @@ status_t OfflineProcess::Process(const uint32_t client_id, native_handle_delete(input_nh1); native_handle_delete(output_nh); delete pproc_params; - return NO_MEMORY; + return -ENOMEM; } pproc_params->streamId = client_id; @@ -441,7 +418,7 @@ status_t OfflineProcess::Process(const uint32_t client_id, QMMF_ERROR("%s: No jpeg encoder instance for client %d", __func__, client_id); ReleaseRequestData(pproc_params); - return BAD_VALUE; + return -EINVAL; } QMMF_INFO("pproc instance: %p", pproc_instance); @@ -492,7 +469,7 @@ status_t OfflineProcess::Process(const uint32_t client_id, remote_cb_handle_(client_id)->NotifyOfflineProcData(out_buf.buffer_id, 0); ReleaseRequestData(pproc_params); - return NO_ERROR; + return 0; } requests_lock_.lock(); @@ -500,7 +477,7 @@ status_t OfflineProcess::Process(const uint32_t client_id, requests_lock_.unlock(); QMMF_INFO("%s: Exit client_id %d", __func__, client_id); - return NO_ERROR; + return 0; } status_t OfflineProcess::Destroy(const uint32_t client_id) { @@ -509,7 +486,7 @@ status_t OfflineProcess::Destroy(const uint32_t client_id) { std::unique_lock client_lock(client_pproc_lock_); if(!IsClientFound(client_id)) { QMMF_ERROR("%s Error: Client %d not found.", __func__, client_id); - return BAD_VALUE; + return -EINVAL; } { @@ -542,7 +519,7 @@ status_t OfflineProcess::Destroy(const uint32_t client_id) { if (!pproc_instance) { QMMF_ERROR("%s: No jpeg encoder instance for client %d!", client_id, __func__); - return BAD_VALUE; + return -EINVAL; } QMMF_INFO("%s: pproc instance: %p", __func__, pproc_instance); @@ -555,11 +532,10 @@ status_t OfflineProcess::Destroy(const uint32_t client_id) { client_pproc_map_.erase(client_id); pCameraPostProcDestroy(pproc_instance); - pCameraPostProcRelease(pproc_instance); pproc_instance = nullptr; QMMF_INFO("%s: Exit client_id %d", __func__, client_id); - return NO_ERROR; + return 0; } void OfflineProcess::ReleaseRequestData(PostProcSessionParams* params) { @@ -604,16 +580,14 @@ void OfflineProcess::NotifyOfflineProc(const uint32_t& client_id, } } -int32_t OfflineCb(PostProcSessionParams* pproc_params, +void OfflineCb(PostProcSessionParams* pproc_params, uint32_t out_size, void* user_data) { if (!pproc_params) { QMMF_ERROR("%s: pproc_params is null", __func__); - return BAD_VALUE; } if (!user_data) { QMMF_ERROR("%s: user_data is null", __func__); - return BAD_VALUE; } OfflineCbData* cb_data = reinterpret_cast(user_data); @@ -622,7 +596,6 @@ int32_t OfflineCb(PostProcSessionParams* pproc_params, int32_t out_buf_fd = pproc_params->outHandle[0].phHandle->data[0]; enc->NotifyOfflineProc(client, out_buf_fd, out_size, pproc_params); - return NO_ERROR; } }; // namespace qmmf. diff --git a/recorder/src/service/qmmf_offline_proc_impl.h b/recorder/src/service/qmmf_offline_proc_impl.h index 59a8e16..62f1b85 100644 --- a/recorder/src/service/qmmf_offline_proc_impl.h +++ b/recorder/src/service/qmmf_offline_proc_impl.h @@ -5,6 +5,12 @@ #pragma once +#include + +#include +#include +#include + #include #include "common/cameraadaptor/qmmf_camera3_utils.h" @@ -102,7 +108,7 @@ struct OfflineCbData { uint32_t client_id; }; -int32_t OfflineCb(PostProcSessionParams* pproc_params, +void OfflineCb(PostProcSessionParams* pproc_params, uint32_t out_size, void* user_data); diff --git a/recorder/src/service/qmmf_recorder_impl.cc b/recorder/src/service/qmmf_recorder_impl.cc index a590cd2..2515ab3 100644 --- a/recorder/src/service/qmmf_recorder_impl.cc +++ b/recorder/src/service/qmmf_recorder_impl.cc @@ -121,7 +121,7 @@ status_t RecorderImpl::Init(const RemoteCallbackHandle& remote_cb_handle) { offline_process_ = new OfflineProcess; if (!offline_process_) { QMMF_ERROR("%s: Can't Create OfflineProcess Instance!", __func__); - return NO_MEMORY; + return -ENOMEM; } status_t ret = offline_process_->Init(remote_cb_handle); diff --git a/recorder/src/service/qmmf_recorder_service.cc b/recorder/src/service/qmmf_recorder_service.cc index 4db374e..40d5f1e 100644 --- a/recorder/src/service/qmmf_recorder_service.cc +++ b/recorder/src/service/qmmf_recorder_service.cc @@ -934,16 +934,18 @@ status_t RecorderService::SetupSocket() { return 0; } -status_t RecorderService::ReadRequest (int socket, void *buffer, size_t size) { - - ssize_t bytes_read = recv(socket, buffer, size, 0); - - if (bytes_read > 0) { - QMMF_VERBOSE("%s: read %zd bytes from client socket: %d", - __func__, bytes_read, socket); - return static_cast(bytes_read); - } +status_t RecorderService::ReadRequest(int socket, void *buffer, size_t size) { + struct msghdr msg = {0}; + struct iovec io; + char cmsgbuf[CMSG_SPACE(1024)] = {0}; + io.iov_base = buffer; + io.iov_len = size; + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + ssize_t bytes_read = recvmsg(socket, &msg, 0); if (bytes_read == -1) { QMMF_ERROR("%s: Receive failed: %s", __func__, strerror(errno)); return -errno; @@ -953,6 +955,24 @@ status_t RecorderService::ReadRequest (int socket, void *buffer, size_t size) { return 0; } + // Extract file descriptors + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int32_t *fds = reinterpret_cast(CMSG_DATA(cmsg)); + int fd_count = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int32_t); + for (int i = 0; i < fd_count; ++i) { + fds_.push_back(fds[i]); + } + } + } + + if (bytes_read > 0) { + QMMF_VERBOSE("%s: read %zd bytes from client socket: %d", __func__, + bytes_read, socket); + return static_cast(bytes_read); + } + return -EINVAL; } @@ -1434,6 +1454,119 @@ void RecorderService::ProcessRequest(int client_socket, RecorderClientReqMsg req add_vers(QMMF_CURRENT_INTERFACE_VER); break; } + case RECORDER_SERVICE_CMDS::RECORDER_GET_OFFLINE_CAMERA_PARAMS: { + const auto &msg = req_msg.get_offline_camera_params(); + uint32_t client_id = msg.client_id(); + + OfflineCameraInputParams in_params{}; + + int n_cam = std::min(2, msg.in_params().camera_id_size()); + for (int i = 0; i < n_cam; ++i) { + in_params.camera_id[i] = msg.in_params().camera_id(i); + } + in_params.width = msg.in_params().width(); + in_params.height = msg.in_params().height(); + + OfflineCameraOutputParams out_params{}; + + status_t st = GetOfflineParams(client_id, in_params, out_params); + resp_msg.set_command( + RECORDER_SERVICE_CMDS::RECORDER_GET_OFFLINE_CAMERA_PARAMS); + resp_msg.set_status(st); + if (st == 0) { + auto *out_msg = resp_msg.mutable_get_offline_camera_params_resp() + ->mutable_out_params(); + out_msg->set_size(out_params.size); + } + break; + } + case RECORDER_SERVICE_CMDS::RECORDER_CREATE_OFFLINE_CAMERA: { + const auto &msg = req_msg.create_offline_camera(); + uint32_t client_id = msg.client_id(); + const auto &p = msg.params(); + + OfflineCameraCreateParams params{}; + + int n_cam = std::min(2, p.camera_id_size()); + for (int i = 0; i < n_cam; ++i) { + params.camera_id[i] = p.camera_id(i); + } + + params.in_buffer.width = p.in_buffer().width(); + params.in_buffer.height = p.in_buffer().height(); + params.in_buffer.format = + static_cast(p.in_buffer().format()); + + params.out_buffer.width = p.out_buffer().width(); + params.out_buffer.height = p.out_buffer().height(); + params.out_buffer.format = + static_cast(p.out_buffer().format()); + + params.process_mode = static_cast(p.process_mode()); + + status_t st = CreateOfflineProcess(client_id, params); + resp_msg.set_command(RECORDER_SERVICE_CMDS::RECORDER_CREATE_OFFLINE_CAMERA); + resp_msg.set_status(st); + break; + } + case RECORDER_SERVICE_CMDS::RECORDER_PROCESS_OFFLINE_CAMERA: { + const auto &msg = req_msg.process_offline_camera(); + uint32_t client_id = msg.client_id(); + const auto &p = msg.process_params(); + + // Build BnBuffer wrappers for the input/output buffers. + BnBuffer in_buf0{}; + BnBuffer in_buf1{}; + BnBuffer out_buf{}; + + in_buf0.ion_fd = -1; + in_buf1.ion_fd = -1; + out_buf.ion_fd = -1; + in_buf0.buffer_id = -1; + in_buf1.buffer_id = -1; + out_buf.buffer_id = -1; + + if (p.in_buf_fd_size() > 0) { + in_buf0.ion_fd = fds_[0]; + in_buf0.buffer_id = p.in_buf_fd(0); + } + + out_buf.ion_fd = fds_[1]; + out_buf.buffer_id = p.out_buf_fd(); + + CameraMetadata meta; + const std::string &m = p.meta(); + if (!m.empty()) { + uint8_t *raw_buf = new uint8_t[m.size()]; + camera_metadata_t *meta_buf = + ::qmmf::CameraMetadata::copy_camera_metadata( + raw_buf, m.size(), + reinterpret_cast(m.data())); + if (meta_buf) { + meta.acquire(meta_buf); + } else { + delete[] raw_buf; + } + } + + status_t st = + ProcOfflineProcess(client_id, in_buf0, in_buf1, out_buf, meta); + resp_msg.set_command( + RECORDER_SERVICE_CMDS::RECORDER_PROCESS_OFFLINE_CAMERA); + resp_msg.set_status(st); + break; + } + + case RECORDER_SERVICE_CMDS::RECORDER_DESTROY_OFFLINE_CAMERA: { + const auto &msg = req_msg.destroy_offline_camera(); + uint32_t client_id = msg.client_id(); + + status_t st = DestroyOfflineProcess(client_id); + resp_msg.set_command( + RECORDER_SERVICE_CMDS::RECORDER_DESTROY_OFFLINE_CAMERA); + resp_msg.set_status(st); + break; + } default: QMMF_WARN ("%s: cmd: %u, Not sending.", __func__, req_msg.command()); @@ -1525,6 +1658,7 @@ void RecorderService::MainLoop() { // Deserialize the received data using protobuf ParseRequest(client_socket, socket_recv_buf_, bytes_read); memset(socket_recv_buf_, 0, bytes_read); + fds_.clear(); } ++it; } @@ -2476,8 +2610,22 @@ void RecorderServiceCallbackProxy::NotifySnapshotData(uint32_t camera_id, uint32 __func__, camera_id, imgcount); } -void RecorderServiceCallbackProxy::NotifyOfflineProcData(int32_t buf_fd, uint32_t out_size) { +void RecorderServiceCallbackProxy::NotifyOfflineProcData(int32_t buf_fd, + uint32_t out_size) { + QMMF_DEBUG("%s: Enter", __func__); + + RecorderClientCallbacksAsync async_msg; + async_msg.set_cmd( + RECORDER_SERVICE_CB_CMDS::RECORDER_NOTIFY_OFFLINE_CAMERA_DATA); + + NotifyOfflineCameraDataMsg *data = async_msg.mutable_offline_camera_data(); + + data->set_buf_fd(buf_fd); + data->set_encoded_size(out_size); + + SendCallbackData(async_msg); + QMMF_DEBUG("%s: Exit", __func__); } void RecorderServiceCallbackProxy::NotifyVideoTrackData(uint32_t track_id, diff --git a/recorder/src/service/qmmf_recorder_service.h b/recorder/src/service/qmmf_recorder_service.h index a203124..7e38789 100644 --- a/recorder/src/service/qmmf_recorder_service.h +++ b/recorder/src/service/qmmf_recorder_service.h @@ -392,6 +392,8 @@ class RecorderService : public IRecorderService { bool run_; // Map of client sockets and their client_ids . std::map client_sockets_; + // Vector of offline camera buffers fds + std::vector fds_; #endif // HAVE_BINDER std::mutex lock_; From f3bdcec0661e50bd51d85f13ed62b98c8422e135 Mon Sep 17 00:00:00 2001 From: Jai Shiv Date: Wed, 27 May 2026 14:14:55 +0530 Subject: [PATCH 4/4] cam-server: fix duplicate client ID for rapid connect - On the non-binder path, client connection is split into two phases: Phase 1 (RECORDER_CONNECT) - allocates client ID, adds to death_notifier_list_ Phase 2 (CALLBACK_SOCKET_READY) - sets up callback, adds to remote_cb_list_ - GetUniqueClientID() was only checking remote_cb_list_ to determine if an ID was free. Since remote_cb_list_ is not populated until Phase 2, a second client connecting immediately after the first (before Phase 2 completes) would see an empty remote_cb_list_ and get assigned the same client ID, causing duplicates. - Fix: use active_client_ids_ as the single source of truth for ID reservation. Signed-off-by: Jai Shiv Signed-off-by: Girish K --- recorder/src/service/qmmf_recorder_service.cc | 9 +++++++++ recorder/src/service/qmmf_recorder_service.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/recorder/src/service/qmmf_recorder_service.cc b/recorder/src/service/qmmf_recorder_service.cc index 40d5f1e..dbd94c5 100644 --- a/recorder/src/service/qmmf_recorder_service.cc +++ b/recorder/src/service/qmmf_recorder_service.cc @@ -1733,6 +1733,8 @@ status_t RecorderService::Connect(const std::shared_ptrRegisterClient(*client_id); NotifyClientDeath notify_death = [this, capture_client_id = *client_id] { @@ -1743,6 +1745,7 @@ status_t RecorderService::Connect(const std::shared_ptr(notify_death); if (!death_notifier.get()) { QMMF_ERROR("%s: Unable to allocate death notifier!", __func__); + active_client_ids_.erase(*client_id); return -ENODEV; } @@ -1790,6 +1793,7 @@ status_t RecorderService::Disconnect(uint32_t client_id) { death_notifier_list_.erase(client_id); remote_cb_list_.erase(client_id); + active_client_ids_.erase(client_id); if (death_notifier_list_.empty() && remote_cb_list_.empty()) { if (recorder_) { @@ -2378,6 +2382,7 @@ status_t RecorderService::DisconnectInternal(const uint32_t client_id) { #endif death_notifier_list_.erase(client_id); remote_cb_list_.erase(client_id); + active_client_ids_.erase(client_id); if (death_notifier_list_.empty() && remote_cb_list_.empty()) { if (recorder_) { @@ -2400,7 +2405,11 @@ status_t RecorderService::GetVendorTagDescriptor(std::shared_ptr> death_notifier_list_; // Map of client ids and their callback handlers. std::map> remote_cb_list_; + // Set of active client IDs reserved at Connect time. + std::set active_client_ids_; int socket_; std::string socket_path_; char* socket_recv_buf_;