4 * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: YoungHun Kim <yh8004.kim@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 #include "muse_core_internal.h"
23 #include "muse_server_private.h"
25 #define MSG_THREAD_NAME "msg"
26 #define DATA_THREAD_NAME "data"
28 #define DATA_WORKER_QDATA_MAX_SIZE (3840 * 2160 * 4) /* UHD BGRA8888 */
29 #define UNLIMITED_INSTANCE -1
31 static void _ms_ipc_data_ch_init(muse_module_h m);
32 static void _ms_ipc_data_ch_deinit(muse_module_h m);
33 static void _ms_ipc_module_data_ch_cleanup(muse_module_h m);
34 static void _ms_ipc_module_msg_ch_cleanup(muse_module_h m);
35 static void _ms_ipc_module_cleanup(muse_module_h m);
36 static gboolean _ms_ipc_module_instance_creation_is_allowed(int module_idx);
37 static gboolean _ms_ipc_get_module_idx(muse_module_h m, void *jobj);
38 static gboolean _ms_ipc_dispatch_create(muse_module_h m, void *jobj);
39 static gboolean _ms_ipc_dispatch_destroy(muse_module_h m);
40 static gboolean _ms_ipc_dispatch_no_instance(muse_module_h m, void *jobj);
41 static gpointer _ms_ipc_dispatch_worker(gpointer data);
42 static gboolean _ms_ipc_data_processing(int fd, muse_recv_data_head_t *header, muse_channel_info_t *ch);
43 static gpointer _ms_ipc_data_worker(gpointer data);
45 static void _ms_ipc_data_ch_init(muse_module_h m)
47 muse_return_if_fail(m);
49 m->ch[MUSE_CHANNEL_DATA].data_queue = g_queue_new();
50 g_mutex_init(&m->ch[MUSE_CHANNEL_DATA].data_mutex);
51 g_cond_init(&m->ch[MUSE_CHANNEL_DATA].data_cond);
54 static void _ms_ipc_data_ch_deinit(muse_module_h m)
56 muse_return_if_fail(m);
58 g_mutex_lock(&m->ch[MUSE_CHANNEL_DATA].data_mutex);
59 g_queue_free(m->ch[MUSE_CHANNEL_DATA].data_queue);
60 m->ch[MUSE_CHANNEL_DATA].data_queue = NULL;
61 g_cond_broadcast(&m->ch[MUSE_CHANNEL_DATA].data_cond);
62 g_mutex_unlock(&m->ch[MUSE_CHANNEL_DATA].data_mutex);
64 g_mutex_clear(&m->ch[MUSE_CHANNEL_DATA].data_mutex);
65 g_cond_clear(&m->ch[MUSE_CHANNEL_DATA].data_cond);
68 static void _ms_ipc_module_data_ch_cleanup(muse_module_h m)
70 muse_return_if_fail(m);
72 if (!m->ch[MUSE_CHANNEL_DATA].thread)
75 g_thread_join(m->ch[MUSE_CHANNEL_DATA].thread);
76 m->ch[MUSE_CHANNEL_DATA].thread = NULL;
78 _ms_ipc_data_ch_deinit(m);
80 LOGD("[close] [%d] MUSE_CHANNEL_DATA", m->ch[MUSE_CHANNEL_DATA].sock_fd);
81 muse_core_connection_close(m->ch[MUSE_CHANNEL_DATA].sock_fd);
85 static void _ms_ipc_module_msg_ch_cleanup(muse_module_h m)
87 muse_return_if_fail(m);
88 muse_return_if_fail(m->ch[MUSE_CHANNEL_MSG].thread);
90 SECURE_LOGD("[close] [%d] MUSE_CHANNEL_MSG %p", m->ch[MUSE_CHANNEL_MSG].sock_fd, m);
91 muse_core_connection_close(m->ch[MUSE_CHANNEL_MSG].sock_fd);
93 SECURE_LOGD("msg thread (%p) exit", m->ch[MUSE_CHANNEL_MSG].thread);
94 g_thread_unref(m->ch[MUSE_CHANNEL_MSG].thread);
95 m->ch[MUSE_CHANNEL_MSG].thread = NULL;
98 static void _ms_ipc_module_cleanup(muse_module_h m)
100 muse_return_if_fail(m);
102 _ms_ipc_module_data_ch_cleanup(m);
104 _ms_ipc_module_msg_ch_cleanup(m);
106 ms_connection_unregister(m);
108 g_mutex_clear(&m->dispatch_lock);
110 memset(m, 0, sizeof(muse_module_t));
112 LOGI("[module %p] EXIT pid %d handle %zd created %d", m, m->pid, m->handle, m->is_created);
116 static gboolean _ms_ipc_module_instance_creation_is_allowed(int module_idx)
118 int max_instance, created_module_instance_count;
120 muse_return_val_if_fail(ms_check_module_idx(module_idx), FALSE);
122 max_instance = ms_config_get_max_instance(module_idx);
123 created_module_instance_count = muse_server_get_module_instance_count(module_idx);
125 if (max_instance == UNLIMITED_INSTANCE || created_module_instance_count < max_instance) {
128 LOGW("The number (%d) of created module instance is over the value of max instance (%d)",
129 created_module_instance_count, max_instance);
134 static gboolean _ms_ipc_get_module_idx(muse_module_h m, void *jobj)
136 muse_return_val_if_fail(m, FALSE);
137 muse_return_val_if_fail(jobj, FALSE);
139 if (!muse_core_msg_object_get_value(MSG_KEY_MODULE_INDEX, jobj, MUSE_TYPE_INT, &m->idx)) {
140 LOGE("Failed to get the value of module index");
147 static gboolean _ms_ipc_dispatch_create(muse_module_h m, void *jobj)
149 int pid, dispatch_ret = MM_ERROR_NONE;
150 g_autoptr(GMutexLocker) locker = NULL;
152 muse_return_val_if_fail(m, FALSE);
153 muse_return_val_if_fail(jobj, FALSE);
155 locker = g_mutex_locker_new(&m->dispatch_lock);
157 if (!_ms_ipc_get_module_idx(m, jobj)) {
158 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_DEBUG_INFO_DUMP);
162 m->ch[MUSE_CHANNEL_MSG].dll_handle = ms_module_open(m->idx);
164 if (!_ms_ipc_module_instance_creation_is_allowed(m->idx)) {
165 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_RESOURCE_NOT_AVAILABLE);
169 if (muse_core_msg_object_get_value(MSG_KEY_PID, jobj, MUSE_TYPE_INT, &pid) && m->pid != pid)
170 LOGW("connected pid [%d] msg [%d] is different", m->pid, pid);
172 ms_connection_register(m);
174 if (muse_server_is_ready())
175 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_CREATE_SERVER_ACK);
177 LOGW("Do not send server acknowledgement because muse server is actually not ready");
179 _ms_ipc_data_ch_init(m);
181 LOGD("module fd: %d dll_handle: %p", m->ch[MUSE_CHANNEL_MSG].sock_fd, m->ch[MUSE_CHANNEL_MSG].dll_handle);
182 dispatch_ret = ms_module_dispatch(m);
184 if (dispatch_ret != MM_ERROR_NONE) {
185 LOGE("create dispatch failed 0x%x, clean up module", dispatch_ret);
189 m->is_created = TRUE;
196 static gboolean _ms_ipc_dispatch_destroy(muse_module_h m)
198 int dispatch_ret = MM_ERROR_NONE;
199 g_autoptr(GMutexLocker) locker = NULL;
201 muse_return_val_if_fail(m, FALSE);
203 locker = g_mutex_locker_new(&m->dispatch_lock);
205 dispatch_ret = ms_module_dispatch(m);
206 if (dispatch_ret != MM_ERROR_NONE) {
207 LOGE("destroy dispatch failed 0x%x", dispatch_ret);
214 static gboolean _ms_ipc_dispatch_no_instance(muse_module_h m, void *jobj)
216 muse_return_val_if_fail(m, FALSE);
217 muse_return_val_if_fail(jobj, FALSE);
219 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&m->dispatch_lock);
221 if (!_ms_ipc_get_module_idx(m, jobj)) {
222 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_DEBUG_INFO_DUMP);
226 m->ch[MUSE_CHANNEL_MSG].dll_handle = ms_module_open(m->idx);
228 if (!_ms_ipc_module_instance_creation_is_allowed(m->idx)) {
229 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_RESOURCE_NOT_AVAILABLE);
233 ms_connection_register(m);
235 _ms_ipc_data_ch_init(m);
237 ms_module_dispatch(m);
239 SECURE_LOGW("[module %p] [loaded value %d]", m, ms_module_get_loaded_dllsym(m->idx));
244 static gpointer _ms_ipc_dispatch_worker(gpointer data)
248 muse_module_h m = NULL;
249 gboolean attempt_to_dispatch = TRUE;
251 char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
253 muse_return_val_if_fail(data, NULL);
255 m = (muse_module_h)data;
257 fd = m->ch[MUSE_CHANNEL_MSG].sock_fd;
258 m->ch[MUSE_CHANNEL_MSG].thread = g_thread_self();
260 LOGI("Enter %d module %p thread %p", fd, m, m->ch[MUSE_CHANNEL_MSG].thread);
262 while (attempt_to_dispatch) {
263 memset(m->recv_msg, 0x00, sizeof(m->recv_msg));
265 for (i = 0; i < MUSE_NUM_FD; i++)
266 m->ch[MUSE_CHANNEL_MSG].tbm_fd[i] = -1;
268 len = muse_core_msg_recv_fd(fd, m->recv_msg, MUSE_MSG_MAX_LENGTH, m->ch[MUSE_CHANNEL_MSG].tbm_fd);
270 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
271 LOGE("[%s] [%d] recv : %s (%d)", ms_config_get_host_name(m->idx), fd, err_msg, errno);
272 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_SHUTDOWN);
273 attempt_to_dispatch = FALSE;
278 while (attempt_to_dispatch && m->msg_offset < len && ms_is_server_ready()) {
279 jobj = muse_core_msg_object_new(m->recv_msg + m->msg_offset, &parse_len, NULL);
281 LOGE("jobj is null");
282 attempt_to_dispatch = FALSE;
286 if (muse_core_msg_object_get_value(MSG_KEY_API, jobj, MUSE_TYPE_INT, &m->api)) {
289 SECURE_LOGI("CREATE module %p %d", m, fd);
290 attempt_to_dispatch = _ms_ipc_dispatch_create(m, jobj);
293 SECURE_LOGI("DESTROY module %p %d", m, fd);
294 attempt_to_dispatch = _ms_ipc_dispatch_destroy(m);
297 if (m->is_created) /* handle based */
298 ms_module_dispatch(m);
300 attempt_to_dispatch = _ms_ipc_dispatch_no_instance(m, jobj);
304 muse_core_msg_object_free(jobj);
306 m->msg_offset += parse_len;
307 parse_len = len - parse_len;
311 _ms_ipc_module_cleanup(m);
315 #ifdef MUSE_GCOV_TEST
316 muse_core_gcov_flush();
322 static gboolean _ms_ipc_data_processing(int fd, muse_recv_data_head_t *header, muse_channel_info_t *ch)
324 char *raw_data = NULL;
325 muse_server_h ms = ms_get_instance();
327 muse_return_val_if_fail(ms, FALSE);
329 if (!(fd > 0 && header && ch)) {
330 LOGE("invalid param %d %p %p", fd, header, ch);
331 goto _PROCESSING_FAILED;
335 if (header->marker != MUSE_DATA_HEAD) {
336 LOGE("invalid marker 0x%x", header->marker);
337 goto _PROCESSING_FAILED;
340 /* check data size */
341 if (header->size > DATA_WORKER_QDATA_MAX_SIZE) {
342 LOGE("invalid data size %d", header->size);
343 goto _PROCESSING_FAILED;
346 /* allocation data */
347 raw_data = (char *)g_try_new0(char, header->size + sizeof(muse_recv_data_head_t));
349 LOGE("failed to alloc data %d + %zu", header->size, sizeof(muse_recv_data_head_t));
350 goto _PROCESSING_FAILED;
354 memcpy(raw_data, header, sizeof(muse_recv_data_head_t));
357 if (!muse_core_msg_recv_len(fd, raw_data + sizeof(muse_recv_data_head_t), header->size)) {
358 LOGE("receive data failed - length %d", header->size);
359 goto _PROCESSING_FAILED;
363 g_mutex_lock(&ch->data_mutex);
364 g_queue_push_tail(ch->data_queue, (gpointer)raw_data);
365 g_cond_signal(&ch->data_cond);
366 g_mutex_unlock(&ch->data_mutex);
372 MUSE_G_FREE(raw_data);
374 ms_log_process_info(ms->pid);
379 static gpointer _ms_ipc_data_worker(gpointer data)
381 char recv_buf[MUSE_MSG_LEN_MAX] = {'\0',};
383 muse_module_h m = NULL;
384 muse_channel_info_t *ch = NULL;
386 muse_return_val_if_fail(data, NULL);
388 m = (muse_module_h)data;
389 SECURE_LOGW("module : %p pid %d handle %zd created %d fd %d",
390 m, m->pid, m->handle, m->is_created, m->ch[MUSE_CHANNEL_MSG].sock_fd);
392 muse_return_val_if_fail(muse_server_module_is_valid(m), NULL);
394 fd = m->ch[MUSE_CHANNEL_DATA].sock_fd;
395 ch = &m->ch[MUSE_CHANNEL_DATA];
399 if (!muse_core_msg_recv_len(fd, recv_buf, sizeof(muse_recv_data_head_t)))
402 if (!_ms_ipc_data_processing(fd, (muse_recv_data_head_t *)recv_buf, ch)) {
403 LOGE("ipc data processing failed");
413 gboolean ms_ipc_create_msg_dispatch_worker(muse_module_h m)
415 GThread *thread = NULL;
416 GError *error = NULL;
417 muse_server_h ms = ms_get_instance();
418 ms_connection_t *connection = NULL;
422 muse_return_val_if_fail(ms, FALSE);
423 muse_return_val_if_fail(ms_is_server_ready(), FALSE);
424 muse_return_val_if_fail(muse_server_module_is_valid(m), FALSE);
426 connection = ms->connection;
427 muse_return_val_if_fail(connection, FALSE);
429 ms_connection_lock(connection);
431 SECURE_LOGD("[PID %d module %p] module's msg channel fd : %d", m->pid, m, m->ch[MUSE_CHANNEL_MSG].sock_fd);
433 thread = g_thread_try_new(MSG_THREAD_NAME, _ms_ipc_dispatch_worker, (gpointer)m, &error);
435 LOGE("[module %p] thread creation failed : %s", m, error->message);
437 ms_log_process_info(ms->pid);
438 ms_connection_unlock(connection);
442 LOGD("Leave module %p thread %p", m, thread);
444 ms_connection_unlock(connection);
449 gboolean ms_ipc_create_data_dispatch_worker(muse_module_h m)
451 GError *error = NULL;
452 muse_server_h ms = ms_get_instance();
453 ms_connection_t *connection = NULL;
457 muse_return_val_if_fail(ms, FALSE);
458 muse_return_val_if_fail(ms_is_server_ready(), FALSE);
459 muse_return_val_if_fail(muse_server_module_is_valid(m), TRUE);
461 connection = ms->connection;
462 muse_return_val_if_fail(connection, FALSE);
464 ms_connection_lock(connection);
466 m->ch[MUSE_CHANNEL_DATA].thread = g_thread_try_new(DATA_THREAD_NAME, _ms_ipc_data_worker, (gpointer)m, &error);
467 if (!m->ch[MUSE_CHANNEL_DATA].thread) {
468 LOGE("thread creation failed : %s", error->message);
470 ms_log_process_info(ms->pid);
471 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_RESOURCE_NOT_AVAILABLE);
472 muse_core_connection_close(m->ch[MUSE_CHANNEL_MSG].sock_fd);
473 ms_connection_unlock(connection);
479 ms_connection_unlock(connection);