4618efd7fdff018e3f7071d7770f6f7c6f8331ab
[platform/core/multimedia/mmsvc-core.git] / server / src / muse_server_system.c
1 /*
2  * muse-server
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: YoungHun Kim <yh8004.kim@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include "muse_server_private.h"
23 #include <storage.h>
24 #include <system_info.h>
25 #include <runtime_info.h>
26 #include <malloc.h>
27
28 #define MUSE_STORAGE_EXTERNAL_FEATURE           "http://tizen.org/feature/storage.external"
29
30 #define MUSE_STAT_CHECK_COUNT                           3
31 #define MUSE_STAT_TIMER_PERIOD                          1
32
33 enum muse_poweroff_type {
34         MUSE_POWER_OFF_NONE = 0,
35         MUSE_POWER_OFF_POPUP,
36         MUSE_POWER_OFF_DIRECT,
37         MUSE_POWER_OFF_RESTART,
38 };
39
40 #ifdef MUSE_USE_POWER_OFF_STATE_CHANGE
41 static int _ms_system_subscribe_poweroff_state_change(ms_system_t *system);
42 static void _ms_system_unsubscribe_poweroff_state_change(void);
43 static void _ms_poweroff_state_changed_cb(GDBusConnection *con, const gchar *sender_name, const gchar *object_path,
44                         const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data);
45 #endif
46
47 #ifdef MUSE_USE_EXTERNAL_STORAGE_STATE_CHANGE
48 static int _ms_system_subscribe_external_storage_state_change(ms_system_t *system);
49 static void _ms_system_unsubscribe_external_storage_state_change(void);
50 static void _ms_external_storage_state_changed_cb(int storage_id, storage_dev_e dev, storage_state_e state, const char *fstype,
51                         const char *fsuuid, const char *mount_path, bool primary, int flags, void *user_data);
52 #endif
53
54 #ifdef MUSE_USE_RM_READY
55 static int _ms_system_subscribe_resource_manager_state_change(ms_system_t *system);
56 static void _ms_system_unsubscribe_resource_manager_state_change(void);
57 static void _ms_resource_manager_owner_name_changed_cb(GDBusConnection *con, const gchar *sender_name, const gchar *object_path,
58                         const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data);
59 #endif
60
61 static void _ms_system_stat_reset_cb(gpointer user_data);
62 static gboolean _ms_system_cpu_usage_cb(gpointer user_data);
63
64 #ifdef MUSE_USE_POWER_OFF_STATE_CHANGE
65 static int _ms_system_subscribe_poweroff_state_change(ms_system_t *system)
66 {
67         LOGD("Enter");
68
69         muse_return_val_if_fail(system, MM_ERROR_INVALID_ARGUMENT);
70
71         muse_return_val_if_fail(system->connection, MM_ERROR_UNKNOWN);
72
73         system->muse_poweroff_id = g_dbus_connection_signal_subscribe(system->connection, NULL,
74                 MS_POWER_DBUS_INTERFACE, MS_POWER_DBUS_MSG, NULL, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
75                 _ms_poweroff_state_changed_cb, NULL, NULL);
76
77         LOGD("Leave");
78
79         return MM_ERROR_NONE;
80 }
81
82 static void _ms_system_unsubscribe_poweroff_state_change(void)
83 {
84         ms_system_t *system = NULL;
85
86         muse_return_if_fail(ms_get_instance());
87
88         system = ms_get_instance()->system;
89         muse_return_if_fail(system);
90         muse_return_if_fail(system->connection);
91
92         g_dbus_connection_signal_unsubscribe(system->connection, system->muse_poweroff_id);
93 }
94
95 static void _ms_poweroff_state_changed_cb(GDBusConnection *con, const gchar *sender_name, const gchar *object_path,
96                         const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data)
97 {
98         int val_int = 0;
99         ms_cmd_dispatcher_info_t dispatch;
100         ms_system_t *system = NULL;
101         ms_connection_t *connection = NULL;
102         g_autoptr(GMutexLocker) locker = NULL;
103
104         LOGE("received power off signal");
105
106         muse_return_if_fail(ms_get_instance());
107         muse_return_if_fail(object_path);
108         muse_return_if_fail(signal_name);
109         muse_return_if_fail(parameters);
110
111         system = ms_get_instance()->system;
112         muse_return_if_fail(system);
113
114         connection = ms_get_instance()->connection;
115         muse_return_if_fail(connection);
116
117         if (g_strcmp0(object_path, MS_POWER_DBUS_PATH) || g_strcmp0(signal_name, MS_POWER_DBUS_MSG)) {
118                 LOGE("object_path : %s signal_name : %s", object_path, signal_name);
119                 return;
120         }
121
122         g_variant_get(parameters, "(i)", &val_int);
123
124         LOGE("POWER OFF TYPE = %d", val_int);
125
126         /* muse has to restart when MUSE_POWER_OFF_DIRECT and MUSE_POWER_OFF_RESTART */
127         muse_return_if_fail(val_int > MUSE_POWER_OFF_POPUP);
128
129         _ms_system_unsubscribe_poweroff_state_change();
130
131         locker = g_mutex_locker_new(&system->lock);
132
133         ms_connection_lock(connection);
134
135         dispatch.cmd = MUSE_MODULE_COMMAND_SHUTDOWN;
136
137         g_queue_foreach(connection->instance_q, ms_cmd_dispatch_foreach_func, (gpointer)&dispatch);
138
139         ms_connection_unlock(connection);
140
141         exit(EXIT_FAILURE);
142 }
143 #endif
144
145 #ifdef MUSE_USE_EXTERNAL_STORAGE_STATE_CHANGE
146 static int _ms_system_subscribe_external_storage_state_change(ms_system_t *system)
147 {
148         LOGD("Enter");
149
150         int ret = storage_set_changed_cb(STORAGE_TYPE_EXTERNAL, _ms_external_storage_state_changed_cb, system);
151
152         if (ret != STORAGE_ERROR_NONE) {
153                 LOGE("[0x%x] failed to register storage changed callback", ret);
154                 return MUSE_ERR;
155         }
156
157         LOGD("Leave");
158
159         return MM_ERROR_NONE;
160 }
161
162 static void _ms_system_unsubscribe_external_storage_state_change(void)
163 {
164         int ret = storage_unset_changed_cb(STORAGE_TYPE_EXTERNAL, _ms_external_storage_state_changed_cb);
165         if (ret != STORAGE_ERROR_NONE)
166                 LOGE("[0x%x] failed to unregister storage changed callback", ret);
167 }
168
169 static void _ms_external_storage_state_changed_cb(int storage_id, storage_dev_e dev, storage_state_e state, const char *fstype,
170                         const char *fsuuid, const char *mount_path, bool primary, int flags, void *user_data)
171 {
172         ms_cmd_dispatcher_info_t dispatch;
173         ms_system_t *system = (ms_system_t *)user_data;
174         ms_connection_t *connection = NULL;
175
176         muse_return_if_fail(system);
177         muse_return_if_fail(ms_get_instance());
178
179         connection = ms_get_instance()->connection;
180         muse_return_if_fail(connection);
181
182         switch (state) {
183         case STORAGE_STATE_UNMOUNTABLE:
184                 LOGI("[%d] [%s] STORAGE_STATE_UNMOUNTABLE", state, mount_path);
185                 break;
186         case STORAGE_STATE_REMOVED:
187                 LOGI("[%d] [%s] STORAGE_STATE_REMOVED", state, mount_path);
188                 break;
189         case STORAGE_STATE_MOUNTED:
190                 LOGI("[%d] [%s] STORAGE_STATE_MOUNTED", state, mount_path);
191                 break;
192         case STORAGE_STATE_MOUNTED_READ_ONLY:
193                 LOGI("[%d] [%s] STORAGE_STATE_MOUNTED_READ_ONLY", state, mount_path);
194                 break;
195         default:
196                 break;
197         }
198
199         g_mutex_lock(&system->lock);
200
201         ms_connection_lock(connection);
202
203         dispatch.cmd = MUSE_MODULE_COMMAND_EXTERNAL_STORAGE_STATE_CHANGED;
204
205         dispatch.storage.id = storage_id;
206         dispatch.storage.state = state;
207         dispatch.storage.path = mount_path;
208
209         g_queue_foreach(connection->instance_q, ms_cmd_dispatch_foreach_func, (gpointer)&dispatch);
210
211         ms_connection_unlock(connection);
212
213         g_mutex_unlock(&system->lock);
214 }
215 #endif
216
217 #ifdef MUSE_USE_RM_READY
218 static int _ms_system_subscribe_resource_manager_state_change(ms_system_t *system)
219 {
220         LOGD("Enter");
221
222         muse_return_val_if_fail(system, MM_ERROR_INVALID_ARGUMENT);
223
224         muse_return_val_if_fail(system->connection, MM_ERROR_UNKNOWN);
225
226         system->muse_rm_id = g_dbus_connection_signal_subscribe(system->connection, MS_DBUS_SERVICE,
227                 MS_DBUS_INTERFACE, MS_RM_DBUS_MSG, NULL, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
228                 _ms_resource_manager_owner_name_changed_cb, NULL, NULL);
229         LOGD("Leave");
230
231         return MM_ERROR_NONE;
232 }
233
234 static void _ms_system_unsubscribe_resource_manager_state_change(void)
235 {
236         ms_system_t *system = NULL;
237
238         muse_return_if_fail(ms_get_instance());
239
240         system = ms_get_instance()->system;
241
242         muse_return_if_fail(system);
243         muse_return_if_fail(system->connection);
244
245         g_dbus_connection_signal_unsubscribe(system->connection, system->muse_rm_id);
246 }
247
248 static void _ms_resource_manager_owner_name_changed_cb(GDBusConnection *con, const gchar *sender_name, const gchar *object_path,
249                         const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data)
250 {
251         ms_cmd_dispatcher_info_t dispatch;
252         ms_system_t *system = NULL;
253         ms_connection_t *connection = NULL;
254         gchar *owner_name = NULL;
255         gchar *old_owner = NULL;
256         gchar *new_owner = NULL;
257
258         muse_return_if_fail(ms_get_instance());
259         muse_return_if_fail(object_path);
260         muse_return_if_fail(signal_name);
261         muse_return_if_fail(parameters);
262
263         system = ms_get_instance()->system;
264         muse_return_if_fail(system);
265
266         connection = ms_get_instance()->connection;
267         muse_return_if_fail(connection);
268
269         if (g_strcmp0(object_path, MS_DBUS_PATH) || g_strcmp0(signal_name, MS_RM_DBUS_MSG))
270                 return;
271
272         g_variant_get(parameters, "(sss)", &owner_name, &old_owner, &new_owner);
273
274         if (g_strcmp0(owner_name, MS_RM_DBUS_SENDER) || *new_owner == '\0')
275                 goto out;
276
277         g_mutex_lock(&system->lock);
278
279         ms_connection_lock(connection);
280
281         dispatch.cmd = MUSE_MODULE_COMMAND_RESOURCE_MANAGER_SHUTDOWN;
282
283         g_queue_foreach(connection->instance_q, ms_cmd_dispatch_foreach_func, (gpointer)&dispatch);
284         LOGE("resource manager shutdown");
285
286         ms_connection_unlock(connection);
287
288         g_mutex_unlock(&system->lock);
289 out:
290         g_free(owner_name);
291         g_free(old_owner);
292         g_free(new_owner);
293 }
294 #endif
295
296 static void _ms_system_stat_reset_cb(gpointer user_data)
297 {
298         ms_system_t *system = (ms_system_t *)user_data;
299
300         muse_return_if_fail(system);
301
302         LOGI("memset stat id %u", system->st.id);
303         memset(&system->st, 0, sizeof(ms_cpu_jiffies_t));
304 }
305
306 static gboolean _ms_system_cpu_usage_cb(gpointer user_data)
307 {
308         FILE *fp;
309         char buf[MUSE_MSG_LEN_MAX];
310         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
311         unsigned long long u, n, s, i;
312         ms_system_t *system = (ms_system_t *)user_data;
313         int cpu_threshold = ms_config_get_cpu_threshold();
314
315         fp = fopen("/proc/stat", "r");
316         if (!fp)
317                 return G_SOURCE_REMOVE;
318         fgets(buf, sizeof(buf), fp);
319         fclose(fp);
320
321         sscanf(buf, "cpu %llu %llu %llu %llu", &u, &n, &s, &i);
322
323         u = u > system->st.user ? u - system->st.user : 0;
324         n = n > system->st.nice ? n - system->st.nice : 0;
325         s = s > system->st.system ? s - system->st.system : 0;
326         i = i > system->st.idle ? i - system->st.idle : 0;
327
328         system->st.user += u;
329         system->st.nice += n;
330         system->st.system += s;
331         system->st.idle += i;
332
333         if (u + n + s + i == 0) {
334                 LOGD("[#%d] cpu usage is 0%%", system->st.counter);
335                 return G_SOURCE_REMOVE;
336         }
337
338         system->st.usage = (int)(100 * ((double)(u + n + s) / (u + n + s + i)));
339         LOGD("[#%d] cpu usage %d %%", system->st.counter, system->st.usage);
340
341         if (system->st.usage < cpu_threshold) {
342                 LOGD("[#%d] cpu usage (%d) < cpu_threshold (%d)", system->st.counter, system->st.usage, cpu_threshold);
343                 return G_SOURCE_REMOVE;
344         }
345
346         system->st.counter++;
347
348         if (system->st.counter >= MUSE_STAT_CHECK_COUNT) {
349                 if (ms_get_instance())
350                         ms_log_process_info(ms_get_instance()->pid);
351
352                 snprintf(err_msg, sizeof(err_msg), "[CPU BUSY] %d >= %d %%", system->st.usage, cpu_threshold);
353
354                 LOGE("%s", err_msg);
355                 ms_terminate(SIGTERM);
356                 return G_SOURCE_REMOVE;
357         }
358
359         return G_SOURCE_CONTINUE;
360 }
361
362 void ms_system_init(ms_system_t *system)
363 {
364         GError *error = NULL;
365
366         muse_return_if_fail(system);
367
368         LOGD("Enter");
369
370         system->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
371         if (!system->connection) {
372                 if (error) {
373                         LOGE("fail to get gdbus connection (%s)", error->message);
374                         g_error_free(error);
375                 }
376         }
377
378         system->platform_info_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
379         muse_return_if_fail(system->platform_info_table);
380
381         g_mutex_init(&system->lock);
382
383         LOGD("Leave");
384 }
385
386 void ms_system_stat_attach(ms_system_t *system)
387 {
388         muse_return_if_fail(system);
389         muse_return_if_fail(system->st.id == 0);
390
391         system->st.id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
392                                                 MUSE_STAT_TIMER_PERIOD,
393                                                 _ms_system_cpu_usage_cb,
394                                                 (gpointer)system,
395                                                 _ms_system_stat_reset_cb);
396
397         LOGI("add stat id %u", system->st.id);
398 }
399
400 void ms_system_stat_detach(ms_system_t *system)
401 {
402         muse_return_if_fail(system);
403
404         LOGI("remove stat id %u", system->st.id);
405
406         if (system->st.id == 0)
407                 return;
408
409         if (!g_source_remove(system->st.id))
410                 LOGE("Failed to remove %u", system->st.id);
411 }
412
413 void ms_system_deinit(ms_system_t *system)
414 {
415         muse_return_if_fail(system);
416 #ifdef MUSE_USE_POWER_OFF_STATE_CHANGE
417         _ms_system_unsubscribe_poweroff_state_change();
418 #endif
419 #ifdef MUSE_USE_EXTERNAL_STORAGE_STATE_CHANGE
420         _ms_system_unsubscribe_external_storage_state_change();
421 #endif
422 #ifdef MUSE_USE_RM_READY
423         _ms_system_unsubscribe_resource_manager_state_change();
424 #endif
425         if (system->connection)
426                 g_object_unref(system->connection);
427
428         g_mutex_clear(&system->lock);
429
430         g_hash_table_destroy(system->platform_info_table);
431
432         g_free(system);
433 }
434
435 int ms_system_get_platform_info(const char *key, bool *value)
436 {
437         int ret = MM_ERROR_NONE;
438         gpointer orig_value;
439         ms_system_t *system = NULL;
440         g_autoptr(GMutexLocker) locker = NULL;
441
442         muse_return_val_if_fail(ms_get_instance(), MM_ERROR_UNKNOWN);
443
444         system = ms_get_instance()->system;
445
446         muse_return_val_if_fail(system, MM_ERROR_INVALID_ARGUMENT);
447         muse_return_val_if_fail(key, MM_ERROR_INVALID_ARGUMENT);
448         muse_return_val_if_fail(value, MM_ERROR_INVALID_ARGUMENT);
449
450         locker = g_mutex_locker_new(&system->lock);
451
452         if (g_hash_table_lookup_extended(system->platform_info_table, key, NULL, &orig_value)) {
453                 *value = GPOINTER_TO_INT(orig_value);
454         } else {
455                 ret = system_info_get_platform_bool(key, value);
456                 switch (ret) {
457                 case SYSTEM_INFO_ERROR_NONE: /* Successful */
458                         g_hash_table_insert(system->platform_info_table, g_strdup(key), GINT_TO_POINTER(*value));
459                         ret = MM_ERROR_NONE;
460                         break;
461                 case SYSTEM_INFO_ERROR_INVALID_PARAMETER: /* Cannot find the key in the model config file */
462                         ret = MM_ERROR_COMMON_ATTR_NOT_EXIST;
463                         break;
464                 case SYSTEM_INFO_ERROR_IO_ERROR: /* An input/output error occurred while reading the value from the model config file */
465                         ret = MM_ERROR_UNKNOWN;
466                         break;
467                 case SYSTEM_INFO_ERROR_PERMISSION_DENIED: /* No permission to use the API */
468                         ret = MM_ERROR_COMMON_INVALID_PERMISSION;
469                         break;
470                 default:
471                         LOGE("system_info_get_platform_bool returns 0x%x", ret);
472                         ret = MM_ERROR_UNKNOWN;
473                         break;
474                 }
475         }
476
477         return ret;
478 }
479
480 void ms_system_subscribe_external_event(ms_system_t *system)
481 {
482 #ifdef MUSE_USE_EXTERNAL_STORAGE_STATE_CHANGE
483         int ret = MM_ERROR_NONE;
484         bool is_external_storage_enabled = false;
485 #endif
486         muse_return_if_fail(system);
487
488 #ifdef MUSE_USE_POWER_OFF_STATE_CHANGE
489         if (_ms_system_subscribe_poweroff_state_change(system) != MM_ERROR_NONE)
490                 LOGE("Fail to subscribe poweroff state change");
491 #endif
492
493 #ifdef MUSE_USE_EXTERNAL_STORAGE_STATE_CHANGE
494         /* external storage feature is supported as of tizen_5.5 */
495         ret = system_info_get_platform_bool(MUSE_STORAGE_EXTERNAL_FEATURE, &is_external_storage_enabled);
496
497         if (ret != MM_ERROR_NONE) /* get the value of mused.conf until tizen_5.0 */
498                 is_external_storage_enabled = (bool)ms_config_is_external_storage_enabled();
499
500         if (is_external_storage_enabled == true && _ms_system_subscribe_external_storage_state_change(system) != MM_ERROR_NONE)
501                 LOGE("Fail to subscribe external storage state change");
502 #endif
503
504 #ifdef MUSE_USE_RM_READY
505         if (_ms_system_subscribe_resource_manager_state_change(system) != MM_ERROR_NONE)
506                 LOGE("Fail to subscribe resource manager state change");
507 #endif
508 }
509
510 int ms_system_get_memory_usage(int pid)
511 {
512         int used_pss = 0;
513         process_memory_info_s *info = NULL;
514         int ret = 0;
515
516         LOGI("Enter");
517
518         if (malloc_trim(0) == 0)
519                 LOGW("It was not possible to release any memory");
520
521         ret = runtime_info_get_process_memory_info(&pid, 1, &info);
522
523         if (RUNTIME_INFO_ERROR_NONE == ret && info)
524                 used_pss = info->pss;
525         else
526                 LOGE("Fail to get process (%d) memory %s", pid, get_error_message(ret));
527
528         MUSE_FREE(info);
529
530         LOGI("Leave");
531
532         return used_pss;
533 }
534
535 gboolean ms_system_get_gdbus(GDBusConnection **connection)
536 {
537         LOGD("Enter");
538
539         ms_system_t *system = NULL;
540
541         muse_return_val_if_fail(ms_get_instance(), FALSE);
542
543         system = ms_get_instance()->system;
544         muse_return_val_if_fail(system, FALSE);
545         muse_return_val_if_fail(system->connection, FALSE);
546
547         *connection = system->connection;
548
549         return TRUE;
550 }
551