Resolve the memory leak issue
[platform/core/multimedia/mm-resource-manager.git] / src / daemon / mm_resource_manager_daemon_dbus.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "daemon/mm_resource_manager_daemon_dbus.h"
18 #include "common/mm_resource_manager_dbus.h"
19 #include "daemon/mm_resource_manager_daemon_priv.h"
20 #include "common/mm_resource_manager_utils.h"
21 #include "daemon/mm_resource_manager_daemon_conf.h"
22
23
24 static MMResourceManager *interface;
25
26 extern int notify_fd[2];
27
28
29 static void __gv2c_array(GVariantIter *gv, mm_resource_manager_dmn_res_request_s **c);
30 static gboolean on_get_conf(MMResourceManager *interface,
31                 GDBusMethodInvocation *invocation, gpointer user_data);
32 static gboolean on_create_handle(MMResourceManager *interface,
33                 GDBusMethodInvocation *invocation, const gint app_class,
34                 gpointer user_data);
35 static gboolean on_destroy_handle(MMResourceManager *interface,
36                 GDBusMethodInvocation *invocation, const guint64 id, gpointer user_data);
37 static gboolean on_commit_handle(MMResourceManager *interface,
38                 GDBusMethodInvocation *invocation, const guint64 id,
39                 GVariant *release, GVariant *acquire, gpointer user_data);
40 static void on_bus_acquired(GDBusConnection *connection, const gchar *name,
41                 gpointer user_data);
42
43 static gboolean _type_is_valid(int type)
44 {
45         if ((type != MM_RESOURCE_MANAGER_NO_RES) &&
46                 (type < MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER || type >= MM_RESOURCE_MANAGER_RES_TYPE_MAX))
47                 return FALSE;
48
49         return TRUE;
50 }
51
52
53 static gboolean _create_pid_file(void)
54 {
55         int fd;
56         struct flock lock;
57         char pid_buf[PID_MSG_LEN] = {'\0',};
58
59         fd = open(PID_FILE, O_WRONLY | O_CREAT, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
60         MM_RM_RETVM_IF(fd < 0, FALSE, "PID file cannot be created (%d)", errno);
61
62         lock.l_type = F_WRLCK;
63         lock.l_start = 0;
64         lock.l_whence = SEEK_SET;
65         lock.l_len = 1000;
66
67         if (fcntl(fd, F_SETLK, &lock) < 0) {
68                 if (errno != EACCES && errno != EAGAIN)
69                         MM_RM_ERROR("Fail to lock pidfile [%d]", errno);
70                 else
71                         MM_RM_ERROR("process is already running");
72
73                 goto error;
74         }
75
76         if (ftruncate(fd, 0) < 0) {
77                 MM_RM_ERROR("Fail to truncate pidfile [%d]", errno);
78                 goto error;
79         }
80
81         memset(pid_buf, 0, sizeof(pid_buf));
82         snprintf(pid_buf, sizeof(pid_buf), "%u", getpid());
83
84         if (write(fd, pid_buf, strlen(pid_buf)) != (int)strlen(pid_buf)) {
85                 MM_RM_ERROR("Fail to write pid to pidfile [%d]", errno);
86                 goto error;
87         }
88
89         close(fd);
90
91         MM_RM_INFO("PID file (%s) is created", PID_FILE);
92         return TRUE;
93
94 error:
95         close(fd);
96         return FALSE;
97 }
98
99 static gboolean _create_ready_file(void)
100 {
101         int fd = -1;
102
103         if ((fd = creat(MM_RESOURCE_MANAGER_READY, 0644)) != -1) {
104                 MM_RM_INFO("ready file(%s) file was created", MM_RESOURCE_MANAGER_READY);
105                 close(fd);
106         } else {
107                 MM_RM_ERROR("cannot create ready file(%s), errno(%d)", MM_RESOURCE_MANAGER_READY, errno);
108                 return FALSE;
109         }
110
111         return TRUE;
112 }
113
114 static gboolean _create_daemon_setup_file(void)
115 {
116         _mmrm_dmn_notify_fork_done();
117         return _create_pid_file() && _create_ready_file();
118 }
119
120 int _mmrm_dmn_dbus_init(void)
121 {
122         interface = mmresource_manager_skeleton_new();
123         MM_RM_RETVM_IF(interface == NULL,
124                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
125                         "Interface cannot be created");
126         g_bus_own_name(G_BUS_TYPE_SYSTEM, RMD_GDBUS_NAME,
127                         G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired, NULL, NULL, NULL,
128                         NULL);
129         return MM_RESOURCE_MANAGER_ERROR_NONE;
130 }
131
132 int _mmrm_dmn_dbus_deinit(void)
133 {
134         MM_RM_RETVM_IF(interface == NULL,
135                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Interface is NULL");
136         g_object_unref(interface);
137         interface = NULL;
138         return MM_RESOURCE_MANAGER_ERROR_NONE;
139 }
140
141 int _mmrm_dmn_dbus_get_conf(mm_resource_manager_res_volume **max_volume,
142                 mm_resource_manager_condition_volume_a **cond_volume, int **max_instance)
143 {
144         mm_resource_manager_conf_s *conf;
145
146         conf = mm_resource_manager_get_conf();
147
148         MM_RM_RETVM_IF(conf == NULL,
149                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
150                         "mm_resource_manager_conf is NULL");
151
152         *max_volume = conf->max_volume;
153         *cond_volume = &conf->condition_volume;
154         *max_instance = conf->max_instance;
155
156         return MM_RESOURCE_MANAGER_ERROR_NONE;
157 }
158
159 int _mmrm_dmn_dbus_create(mm_resource_manager_app_class_e app_class,
160                 mm_resource_manager_id *id)
161 {
162         return _mmrm_dmn_create(app_class, id);
163 }
164
165 int _mmrm_dmn_dbus_destroy(mm_resource_manager_id id)
166 {
167         return _mmrm_dmn_destroy(id);
168 }
169
170 int _mmrm_dmn_dbus_commit(mm_resource_manager_id id, GVariantIter *release,
171                 GVariantIter *acquire, gboolean **is_acquired)
172 {
173         int i;
174         int ret;
175         mm_resource_manager_res_type_e type;
176         mm_resource_manager_dmn_res_request_s *release_requests = NULL, *acquire_requests = NULL;
177         gsize release_len = 0, acquire_len = 0;
178
179         __gv2c_array(release, &release_requests);
180
181         type = release_requests->type;
182         release_len = g_variant_iter_n_children(release);
183
184         if (!_type_is_valid(type)) {
185                 ret = MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
186                 goto out;
187         }
188
189         MM_RM_DEBUG("Commit release request of %"G_GSIZE_FORMAT" items [type %d]", release_len, type);
190
191         __gv2c_array(acquire, &acquire_requests);
192
193         type = acquire_requests->type;
194         acquire_len = g_variant_iter_n_children(acquire);
195
196         if (!_type_is_valid(type)) {
197                 ret = MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
198                 goto out;
199         }
200
201         MM_RM_DEBUG("Commit acquire request of %"G_GSIZE_FORMAT" items [type %d]", acquire_len, type);
202
203         ret = _mmrm_dmn_commit(id, release_requests, acquire_requests);
204         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
205                 MM_RM_ERROR("dmm commit is failed");
206                 goto out;
207         }
208
209         *is_acquired = (gboolean *) g_malloc0_n(acquire_len, sizeof(**is_acquired));
210
211         for (i = 0; acquire_requests[i].type != MM_RESOURCE_MANAGER_NO_RES; i++)
212                 (*is_acquired)[i] = acquire_requests[i].priority_error;
213
214 out:
215         g_free(release_requests);
216         g_free(acquire_requests);
217
218         return ret;
219 }
220
221 int _mmrm_dmn_dbus_release_callback(mm_resource_manager_id id,
222                 mm_resource_manager_res_type_e type,
223                 mm_resource_manager_res_volume volume)
224 {
225         mmresource_manager_emit_release_callback(interface, id, type, volume);
226         return MM_RESOURCE_MANAGER_ERROR_NONE;
227 }
228
229 int _mmrm_dmn_dbus_status_callback(mm_resource_manager_status_e status)
230 {
231         MM_RM_DEBUG("Emitting %d status", status);
232         mmresource_manager_emit_status_callback(interface, status);
233         return MM_RESOURCE_MANAGER_ERROR_NONE;
234 }
235
236 void _mmrm_dmn_notify_fork_done(void)
237 {
238         /* Send "string" through the output side of pipe */
239         MM_RM_RETM_IF(write(notify_fd[1], MSG_DONE, strlen(MSG_DONE) + 1) < 0,
240                 "Failed to notify parent process that child initialization is done");
241
242         MM_RM_DEBUG("[%d] Notify parent process that child initialization is done", notify_fd[1]);
243         close(notify_fd[0]);
244         close(notify_fd[1]);
245 }
246
247 static void __gv2c_array(GVariantIter *gv, mm_resource_manager_dmn_res_request_s **c)
248 {
249         int i;
250         mm_resource_manager_res_type_e type;
251         mm_resource_manager_dmn_res_request_s *rs;
252
253         rs = (mm_resource_manager_dmn_res_request_s *)g_malloc0_n(g_variant_iter_n_children(gv), sizeof(*rs));
254         for (i = 0; g_variant_iter_next(gv, "(ii)", &rs[i].type, &rs[i].volume); i++) {
255                 type = rs[i].type;
256                 if (!_type_is_valid(type)) {
257                         MM_RM_ERROR("type %d is wrong", type);
258                         break;
259                 }
260
261                 MM_RM_DEBUG("(type, vol) = (%d, %d)", type, rs[i].volume);
262         }
263
264         *c = rs;
265 }
266
267 static gboolean on_get_conf(MMResourceManager *interface,
268                 GDBusMethodInvocation *invocation, gpointer user_data)
269 {
270         int i, j;
271         gint error = 0;
272         mm_resource_manager_res_volume *max_volume = NULL;
273         mm_resource_manager_condition_volume_a *cond_volume = NULL;
274         int *max_instance = NULL;
275         GVariantBuilder *res_type_builder;
276         GVariantBuilder *res_cond_builder;
277         GVariantBuilder *res_instance_builder;
278         GVariant *res_type_conf;
279         GVariant *res_cond_conf;
280         GVariant *res_instance_conf;
281
282         error = _mmrm_dmn_dbus_get_conf(&max_volume, &cond_volume, &max_instance);
283
284         res_type_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
285         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
286                 g_variant_builder_add_value(res_type_builder, g_variant_new("i", max_volume[i]));
287
288         res_type_conf = g_variant_builder_end(res_type_builder);
289         g_variant_builder_unref(res_type_builder);
290
291         res_type_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
292         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
293                 res_cond_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
294                 for (j = 0; j < MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX; j++)
295                         g_variant_builder_add_value(res_cond_builder, g_variant_new("i", (*cond_volume)[i][j]));
296
297                 g_variant_builder_add_value(res_type_builder, g_variant_builder_end(res_cond_builder));
298                 g_variant_builder_unref(res_cond_builder);
299         }
300         res_cond_conf = g_variant_builder_end(res_type_builder);
301         g_variant_builder_unref(res_type_builder);
302
303         res_instance_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
304         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
305                 g_variant_builder_add_value(res_instance_builder, g_variant_new("i", max_instance[i]));
306         res_instance_conf = g_variant_builder_end(res_instance_builder);
307         g_variant_builder_unref(res_instance_builder);
308
309         mmresource_manager_complete_conf(interface, invocation, error, res_type_conf, res_cond_conf, res_instance_conf);
310
311         return TRUE;
312 }
313
314 static gboolean on_create_handle(MMResourceManager *interface,
315                 GDBusMethodInvocation *invocation, const gint app_class,
316                 gpointer user_data)
317 {
318         guint64 id = 0;
319         gint error = 0;
320
321         error = _mmrm_dmn_dbus_create(app_class, &id);
322
323         MM_RM_DEBUG("Receive create message for RM");
324
325         mmresource_manager_complete_create(interface, invocation, id, error);
326
327         return TRUE;
328 }
329
330 static gboolean on_destroy_handle(MMResourceManager *interface,
331                 GDBusMethodInvocation *invocation, const guint64 id, gpointer user_data)
332 {
333         gint error = 0;
334
335         MM_RM_DEBUG("Receive destroy message for RM");
336         error = _mmrm_dmn_dbus_destroy(id);
337
338         mmresource_manager_complete_destroy(interface, invocation, error);
339         return TRUE;
340 }
341
342 static gboolean on_commit_handle(MMResourceManager *interface,
343                 GDBusMethodInvocation *invocation, const guint64 id,
344                 GVariant *release, GVariant *acquire, gpointer user_data)
345 {
346         gint error = 0;
347         gboolean ret = TRUE, *flags = NULL;
348         GVariantBuilder *flags_builder;
349         GVariantIter *release_array;
350         GVariantIter *acquire_array;
351         gint i;
352
353         MM_RM_DEBUG("Receive commit message");
354
355         release_array = g_variant_iter_new(release);
356         acquire_array = g_variant_iter_new(acquire);
357
358         error = _mmrm_dmn_dbus_commit(id, release_array, acquire_array, &flags);
359         if (error != MM_RESOURCE_MANAGER_ERROR_NONE) {
360                 MM_RM_ERROR("dbus commit error");
361                 ret = FALSE;
362                 goto out;
363         }
364
365         flags_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
366         for (i = 0; i < g_variant_iter_n_children(acquire_array); i++)
367                 g_variant_builder_add_value(flags_builder, g_variant_new("b", flags[i]));
368         mmresource_manager_complete_commit(interface, invocation, error, g_variant_builder_end(flags_builder));
369
370         g_variant_builder_unref(flags_builder);
371
372 out:
373         g_free(flags);
374         g_variant_iter_free(release_array);
375         g_variant_iter_free(acquire_array);
376
377         return ret;
378 }
379
380 static void on_bus_acquired(GDBusConnection *connection, const gchar *name,
381                 gpointer user_data)
382 {
383         GError *error = NULL;
384         MM_RM_DEBUG("name of bus = %s, userID = %d", name, getuid());
385
386         g_signal_connect(interface, "handle-conf", G_CALLBACK(on_get_conf), NULL);
387         g_signal_connect(interface, "handle-create", G_CALLBACK(on_create_handle), NULL);
388         g_signal_connect(interface, "handle-destroy", G_CALLBACK(on_destroy_handle), NULL);
389         g_signal_connect(interface, "handle-commit", G_CALLBACK(on_commit_handle), NULL);
390
391         if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(interface),
392                         connection, RMD_GDBUS_PATH, &error)) {
393                 MM_RM_ERROR("failed to export interface. msg : %s", error->message);
394                 g_error_free(error);
395                 return;
396         }
397
398         MM_RM_RETM_IF(!_create_daemon_setup_file(), "Daemon cannot create setup file");
399 }