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_server_private.h"
24 #include <system_info.h>
25 #include <runtime_info.h>
28 #define MUSE_STORAGE_EXTERNAL_FEATURE "http://tizen.org/feature/storage.external"
30 #define MUSE_STAT_CHECK_COUNT 3
31 #define MUSE_STAT_TIMER_PERIOD 1
33 enum muse_poweroff_type {
34 MUSE_POWER_OFF_NONE = 0,
36 MUSE_POWER_OFF_DIRECT,
37 MUSE_POWER_OFF_RESTART,
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);
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);
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);
61 static void _ms_system_stat_reset_cb(gpointer user_data);
62 static gboolean _ms_system_cpu_usage_cb(gpointer user_data);
64 #ifdef MUSE_USE_POWER_OFF_STATE_CHANGE
65 static int _ms_system_subscribe_poweroff_state_change(ms_system_t *system)
69 muse_return_val_if_fail(system, MM_ERROR_INVALID_ARGUMENT);
71 muse_return_val_if_fail(system->connection, MM_ERROR_UNKNOWN);
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);
82 static void _ms_system_unsubscribe_poweroff_state_change(void)
84 ms_system_t *system = NULL;
86 muse_return_if_fail(ms_get_instance());
88 system = ms_get_instance()->system;
89 muse_return_if_fail(system);
90 muse_return_if_fail(system->connection);
92 g_dbus_connection_signal_unsubscribe(system->connection, system->muse_poweroff_id);
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)
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;
104 LOGE("received power off signal");
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);
111 system = ms_get_instance()->system;
112 muse_return_if_fail(system);
114 connection = ms_get_instance()->connection;
115 muse_return_if_fail(connection);
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);
122 g_variant_get(parameters, "(i)", &val_int);
124 LOGE("POWER OFF TYPE = %d", val_int);
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);
129 _ms_system_unsubscribe_poweroff_state_change();
131 locker = g_mutex_locker_new(&system->lock);
133 ms_connection_lock(connection);
135 dispatch.cmd = MUSE_MODULE_COMMAND_SHUTDOWN;
137 g_queue_foreach(connection->instance_q, ms_cmd_dispatch_foreach_func, (gpointer)&dispatch);
139 ms_connection_unlock(connection);
145 #ifdef MUSE_USE_EXTERNAL_STORAGE_STATE_CHANGE
146 static int _ms_system_subscribe_external_storage_state_change(ms_system_t *system)
150 int ret = storage_set_changed_cb(STORAGE_TYPE_EXTERNAL, _ms_external_storage_state_changed_cb, system);
152 if (ret != STORAGE_ERROR_NONE) {
153 LOGE("[0x%x] failed to register storage changed callback", ret);
159 return MM_ERROR_NONE;
162 static void _ms_system_unsubscribe_external_storage_state_change(void)
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);
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)
172 ms_cmd_dispatcher_info_t dispatch;
173 ms_system_t *system = (ms_system_t *)user_data;
174 ms_connection_t *connection = NULL;
176 muse_return_if_fail(system);
177 muse_return_if_fail(ms_get_instance());
179 connection = ms_get_instance()->connection;
180 muse_return_if_fail(connection);
183 case STORAGE_STATE_UNMOUNTABLE:
184 LOGI("[%d] [%s] STORAGE_STATE_UNMOUNTABLE", state, mount_path);
186 case STORAGE_STATE_REMOVED:
187 LOGI("[%d] [%s] STORAGE_STATE_REMOVED", state, mount_path);
189 case STORAGE_STATE_MOUNTED:
190 LOGI("[%d] [%s] STORAGE_STATE_MOUNTED", state, mount_path);
192 case STORAGE_STATE_MOUNTED_READ_ONLY:
193 LOGI("[%d] [%s] STORAGE_STATE_MOUNTED_READ_ONLY", state, mount_path);
199 g_mutex_lock(&system->lock);
201 ms_connection_lock(connection);
203 dispatch.cmd = MUSE_MODULE_COMMAND_EXTERNAL_STORAGE_STATE_CHANGED;
205 dispatch.storage.id = storage_id;
206 dispatch.storage.state = state;
207 dispatch.storage.path = mount_path;
209 g_queue_foreach(connection->instance_q, ms_cmd_dispatch_foreach_func, (gpointer)&dispatch);
211 ms_connection_unlock(connection);
213 g_mutex_unlock(&system->lock);
217 #ifdef MUSE_USE_RM_READY
218 static int _ms_system_subscribe_resource_manager_state_change(ms_system_t *system)
222 muse_return_val_if_fail(system, MM_ERROR_INVALID_ARGUMENT);
224 muse_return_val_if_fail(system->connection, MM_ERROR_UNKNOWN);
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);
231 return MM_ERROR_NONE;
234 static void _ms_system_unsubscribe_resource_manager_state_change(void)
236 ms_system_t *system = NULL;
238 muse_return_if_fail(ms_get_instance());
240 system = ms_get_instance()->system;
242 muse_return_if_fail(system);
243 muse_return_if_fail(system->connection);
245 g_dbus_connection_signal_unsubscribe(system->connection, system->muse_rm_id);
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)
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;
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);
263 system = ms_get_instance()->system;
264 muse_return_if_fail(system);
266 connection = ms_get_instance()->connection;
267 muse_return_if_fail(connection);
269 if (g_strcmp0(object_path, MS_DBUS_PATH) || g_strcmp0(signal_name, MS_RM_DBUS_MSG))
272 g_variant_get(parameters, "(sss)", &owner_name, &old_owner, &new_owner);
274 if (g_strcmp0(owner_name, MS_RM_DBUS_SENDER) || *new_owner == '\0')
277 g_mutex_lock(&system->lock);
279 ms_connection_lock(connection);
281 dispatch.cmd = MUSE_MODULE_COMMAND_RESOURCE_MANAGER_SHUTDOWN;
283 g_queue_foreach(connection->instance_q, ms_cmd_dispatch_foreach_func, (gpointer)&dispatch);
284 LOGE("resource manager shutdown");
286 ms_connection_unlock(connection);
288 g_mutex_unlock(&system->lock);
296 static void _ms_system_stat_reset_cb(gpointer user_data)
298 ms_system_t *system = (ms_system_t *)user_data;
300 muse_return_if_fail(system);
302 LOGI("memset stat id %u", system->st.id);
303 memset(&system->st, 0, sizeof(ms_cpu_jiffies_t));
306 static gboolean _ms_system_cpu_usage_cb(gpointer user_data)
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();
315 fp = fopen("/proc/stat", "r");
317 return G_SOURCE_REMOVE;
318 fgets(buf, sizeof(buf), fp);
321 sscanf(buf, "cpu %llu %llu %llu %llu", &u, &n, &s, &i);
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;
328 system->st.user += u;
329 system->st.nice += n;
330 system->st.system += s;
331 system->st.idle += i;
333 if (u + n + s + i == 0) {
334 LOGD("[#%d] cpu usage is 0%%", system->st.counter);
335 return G_SOURCE_REMOVE;
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);
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;
346 system->st.counter++;
348 if (system->st.counter >= MUSE_STAT_CHECK_COUNT) {
349 if (ms_get_instance())
350 ms_log_process_info(ms_get_instance()->pid);
352 snprintf(err_msg, sizeof(err_msg), "[CPU BUSY] %d >= %d %%", system->st.usage, cpu_threshold);
355 ms_terminate(SIGTERM);
356 return G_SOURCE_REMOVE;
359 return G_SOURCE_CONTINUE;
362 void ms_system_init(ms_system_t *system)
364 GError *error = NULL;
366 muse_return_if_fail(system);
370 system->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
371 if (!system->connection) {
373 LOGE("fail to get gdbus connection (%s)", error->message);
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);
381 g_mutex_init(&system->lock);
386 void ms_system_stat_attach(ms_system_t *system)
388 muse_return_if_fail(system);
389 muse_return_if_fail(system->st.id == 0);
391 system->st.id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
392 MUSE_STAT_TIMER_PERIOD,
393 _ms_system_cpu_usage_cb,
395 _ms_system_stat_reset_cb);
397 LOGI("add stat id %u", system->st.id);
400 void ms_system_stat_detach(ms_system_t *system)
402 muse_return_if_fail(system);
404 LOGI("remove stat id %u", system->st.id);
406 if (system->st.id == 0)
409 if (!g_source_remove(system->st.id))
410 LOGE("Failed to remove %u", system->st.id);
413 void ms_system_deinit(ms_system_t *system)
415 muse_return_if_fail(system);
416 #ifdef MUSE_USE_POWER_OFF_STATE_CHANGE
417 _ms_system_unsubscribe_poweroff_state_change();
419 #ifdef MUSE_USE_EXTERNAL_STORAGE_STATE_CHANGE
420 _ms_system_unsubscribe_external_storage_state_change();
422 #ifdef MUSE_USE_RM_READY
423 _ms_system_unsubscribe_resource_manager_state_change();
425 if (system->connection)
426 g_object_unref(system->connection);
428 g_mutex_clear(&system->lock);
430 g_hash_table_destroy(system->platform_info_table);
435 int ms_system_get_platform_info(const char *key, bool *value)
437 int ret = MM_ERROR_NONE;
439 ms_system_t *system = NULL;
440 g_autoptr(GMutexLocker) locker = NULL;
442 muse_return_val_if_fail(ms_get_instance(), MM_ERROR_UNKNOWN);
444 system = ms_get_instance()->system;
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);
450 locker = g_mutex_locker_new(&system->lock);
452 if (g_hash_table_lookup_extended(system->platform_info_table, key, NULL, &orig_value)) {
453 *value = GPOINTER_TO_INT(orig_value);
455 ret = system_info_get_platform_bool(key, value);
457 case SYSTEM_INFO_ERROR_NONE: /* Successful */
458 g_hash_table_insert(system->platform_info_table, g_strdup(key), GINT_TO_POINTER(*value));
461 case SYSTEM_INFO_ERROR_INVALID_PARAMETER: /* Cannot find the key in the model config file */
462 ret = MM_ERROR_COMMON_ATTR_NOT_EXIST;
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;
467 case SYSTEM_INFO_ERROR_PERMISSION_DENIED: /* No permission to use the API */
468 ret = MM_ERROR_COMMON_INVALID_PERMISSION;
471 LOGE("system_info_get_platform_bool returns 0x%x", ret);
472 ret = MM_ERROR_UNKNOWN;
480 void ms_system_subscribe_external_event(ms_system_t *system)
482 #ifdef MUSE_USE_EXTERNAL_STORAGE_STATE_CHANGE
483 int ret = MM_ERROR_NONE;
484 bool is_external_storage_enabled = false;
486 muse_return_if_fail(system);
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");
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);
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();
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");
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");
510 int ms_system_get_memory_usage(int pid)
513 process_memory_info_s *info = NULL;
518 if (malloc_trim(0) == 0)
519 LOGW("It was not possible to release any memory");
521 ret = runtime_info_get_process_memory_info(&pid, 1, &info);
523 if (RUNTIME_INFO_ERROR_NONE == ret && info)
524 used_pss = info->pss;
526 LOGE("Fail to get process (%d) memory %s", pid, get_error_message(ret));
535 gboolean ms_system_get_gdbus(GDBusConnection **connection)
539 ms_system_t *system = NULL;
541 muse_return_val_if_fail(ms_get_instance(), FALSE);
543 system = ms_get_instance()->system;
544 muse_return_val_if_fail(system, FALSE);
545 muse_return_val_if_fail(system->connection, FALSE);
547 *connection = system->connection;