代码路径:vendor/qcom/proprietary/mm-camera/mm-camera2/server-imaging/Android.mk
二、守护进程具体的内容
1) 初始化模块
函数分析:
1) 代码路径:vendor/qcom/proprietary/mm-camera/mm-camera2/server-imaging/server_process.c
函数:server_process_module_init();
概述:对modules_list数组中的模块进行初始化
2) 代码路径:kernel/drivers/media/platform/msm/camera_v2/camera/camera.c
函数:int camera_init_v4l2(struct device *dev, unsigned int *session);
函数ioctl(hal_fd->fd[0], VIDIOC_SUBSCRIBE_EVENT, &subscribe);打开的文件是dev/video0,所以ioctl调用是这video_register_device注册的ioctl_ops。
这里主要关注的两个函是
函数:static unsigned int
camera_v4l2_poll(struct file *filep,
struct poll_table_struct *wait)
作用:select函数通过设备文件的poll函数来检查是否可读、可写。(用户空间的select系统调用对应内核中的poll函数)
参考文章:
关于select的调用方法
关于返回值的解析
在函数camera_v4l2_poll()中的v4l2_event_pending()函数返回的是fh->navailable;
函数:static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev,
const struct timespec *ts)
作用: fh->sequence++;
函数:static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
作用:
fh->sequence--;
例如MSM_CAMERA_NEW_SESSION的过程
HAL层:调用int32_t mm_camera_open(mm_camera_obj_t *my_obj)打开camera
kernel层:static int camera_v4l2_open(struct file *filep) ----> camera_pack_event(filep, MSM_CAMERA_NEW_SESSION, 0, -1, &event);---->
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);----> v4l2_event_queue(vdev, event);----> __v4l2_event_queue_fh(fh, ev, ×tamp);
----> fh->sequence++; ---> static unsigned int camera_v4l2_poll(struct file *filep, struct poll_table_struct *wait) ---> rc |= POLLPRI;
(
POLLPRI表示
可读
)
vendor层:ret = select(select_fds.select_fd + 1, &(select_fds.fds), NULL, NULL, NULL)---> ioctl(fd_info->fd[0], VIDIOC_DQEVENT, &event)--->
fh->sequence--;
通过select系统调用获得kernel的fd的状态改变,从而进行事件的处理,同时调用
VIDIOC_DQEVENT使得fh->sequence--。
3)代码路径:vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/mct/tools/mct_list.c
函数:boolean mct_list_traverse(mct_list_t *mct_list, mct_list_traverse_func traverse,
void *user_data);
函数:mct_list_traverse(listen_fd_list, server_reset_select_fd, &select_fds);
作用:Traverse whole list
函数:static boolean server_reset_select_fd(void *data, void *user_data)
作用:
Camera daemon handles the following types of domain socket messages:
域套接字
消息类型:
Buffer mapping –Handled via type RD_DS_FD_HAL 对应于 hal_ds_fd->fd[0]
消息来源:
hal_ds_fd->session = proc_ret.new_session_info.session_idx;
hal_ds_fd->fd[0] = proc_ret.new_session_info.hal_ds_fd;/***域套接字***/
hal_ds_fd->type = RD_DS_FD_HAL;
VIDIOC_SUBSCRIBE_EVENT
消息类型:
Video node updates from kernel –Handled via type RD_FD_HAL 对应于 hal_fd->fd[0]
消息来源:
hal_fd->fd[0] = open(dev_name, O_RDWR | O_NONBLOCK); /****dev_name = dev/video0***/
hal_fd->type = RD_FD_HAL;
ioctl(hal_fd->fd[0], VIDIOC_SUBSCRIBE_EVENT, &subscribe)
管道
消息类型:
Updates from MCT (over Unix pipe) –Handled via type RD_PIPE_FD_MCT
对应于 mct_fds->fd[0]
消息来源:
mct_fds->session = proc_ret.new_session_info.session_idx;
mct_fds->fd[0] = proc_ret.new_session_info.mct_msg_rd_fd;/***管道***/
mct_fds->fd[1] = proc_ret.new_session_info.mct_msg_wt_fd;/***管道***/
mct_fds->type = RD_PIPE_FD_MCT;
通过下面三个函数将三个不同类型的fd全部添加到
listen_fd_list这个链表中,最后通过mct_list_traverse(listen_fd_list, server_reset_select_fd, &select_fds);获取最大的
fd作为select函数的第一个参数。
listen_fd_list = mct_list_append(listen_fd_list,hal_ds_fd, NULL, NULL)
|---> mct_list_t* mct_list_append(mct_list_t *mct_list, void *data, void *appendto, mct_list_find_func list_find)
|---> new_list = mct_list_new(data);
listen_fd_list = mct_list_append(listen_fd_list, mct_fds, NULL, NULL)
|---> mct_list_t* mct_list_append(mct_list_t *mct_list, void *data, void *appendto, mct_list_find_func list_find)
|---> new_list = mct_list_new(data);
listen_fd_list = mct_list_append(listen_fd_list, hal_fd, NULL, NULL)
|---> mct_list_t* mct_list_append(mct_list_t *mct_list, void *data, void *appendto, mct_list_find_func list_find)
|---> new_list = mct_list_new(data);