Create server setup file after dbus connection
[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
44 static gboolean _create_pid_file(void)
45 {
46         int fd;
47         struct flock lock;
48         char pid_buf[PID_MSG_LEN] = {'\0',};
49
50         fd = open(PID_FILE, O_WRONLY | O_CREAT, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
51         MM_RM_RETVM_IF(fd < 0, FALSE, "PID file cannot be created (%d)", errno);
52
53         lock.l_type = F_WRLCK;
54         lock.l_start = 0;
55         lock.l_whence = SEEK_SET;
56         lock.l_len = 1000;
57
58         if (fcntl(fd, F_SETLK, &lock) < 0) {
59                 if (errno != EACCES && errno != EAGAIN)
60                         MM_RM_ERROR("Fail to lock pidfile [%d]", errno);
61                 else
62                         MM_RM_ERROR("process is already running");
63
64                 goto error;
65         }
66
67         if (ftruncate(fd, 0) < 0) {
68                 MM_RM_ERROR("Fail to truncate pidfile [%d]", errno);
69                 goto error;
70         }
71
72         memset(pid_buf, 0, sizeof(pid_buf));
73         snprintf(pid_buf, sizeof(pid_buf), "%u", getpid());
74
75         if (write(fd, pid_buf, strlen(pid_buf)) != (int)strlen(pid_buf)) {
76                 MM_RM_ERROR("Fail to write pid to pidfile [%d]", errno);
77                 goto error;
78         }
79
80         close(fd);
81
82         MM_RM_INFO("PID file (%s) is created", PID_FILE);
83         return TRUE;
84
85 error:
86         close(fd);
87         return FALSE;
88 }
89
90 static gboolean _create_ready_file(void)
91 {
92         int fd = -1;
93
94         if ((fd = creat(MM_RESOURCE_MANAGER_READY, 0644)) != -1) {
95                 MM_RM_INFO("ready file(%s) file was created", MM_RESOURCE_MANAGER_READY);
96                 close(fd);
97         } else {
98                 MM_RM_ERROR("cannot create ready file(%s), errno(%d)", MM_RESOURCE_MANAGER_READY, errno);
99                 return FALSE;
100         }
101
102         return TRUE;
103 }
104
105 static gboolean _create_daemon_setup_file(void)
106 {
107         _mmrm_dmn_notify_fork_done();
108         return _create_pid_file() && _create_ready_file();
109 }
110
111 int _mmrm_dmn_dbus_init()
112 {
113         interface = mmresource_manager_skeleton_new();
114         MM_RM_RETVM_IF(interface == NULL,
115                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
116                         "Interface cannot be created");
117         g_bus_own_name(G_BUS_TYPE_SYSTEM, RMD_GDBUS_NAME,
118                         G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired, NULL, NULL, NULL,
119                         NULL);
120         return MM_RESOURCE_MANAGER_ERROR_NONE;
121 }
122
123 int _mmrm_dmn_dbus_deinit()
124 {
125         MM_RM_RETVM_IF(interface == NULL,
126                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Interface is NULL");
127         g_object_unref(interface);
128         interface = NULL;
129         return MM_RESOURCE_MANAGER_ERROR_NONE;
130 }
131
132 int _mmrm_dmn_dbus_get_conf(mm_resource_manager_res_volume **max_volume,
133                 mm_resource_manager_condition_volume_a **cond_volume)
134 {
135         mm_resource_manager_conf_s *conf;
136
137         conf = mm_resource_manager_get_conf();
138
139         MM_RM_RETVM_IF(conf == NULL,
140                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
141                         "mm_resource_manager_conf is NULL");
142
143         *max_volume = conf->max_volume;
144         *cond_volume = &conf->condition_volume;
145
146         return MM_RESOURCE_MANAGER_ERROR_NONE;
147 }
148
149 int _mmrm_dmn_dbus_create(mm_resource_manager_app_class_e app_class,
150                 mm_resource_manager_id *id)
151 {
152         return _mmrm_dmn_create(app_class, id);
153 }
154
155 int _mmrm_dmn_dbus_destroy(mm_resource_manager_id id)
156 {
157         return _mmrm_dmn_destroy(id);
158 }
159
160 int _mmrm_dmn_dbus_commit(mm_resource_manager_id id, GVariantIter *release,
161                 GVariantIter *acquire, gboolean **priority_error)
162 {
163         int i;
164         int ret;
165         mm_resource_manager_dmn_res_request_s *release_requests = NULL,
166                         *acquire_requests = NULL;
167
168         MM_RM_DEBUG("Commit release request of %"G_GSIZE_FORMAT" items",
169                         g_variant_iter_n_children(release));
170         __gv2c_array(release, &release_requests);
171
172         MM_RM_DEBUG("Commit acquire request of %"G_GSIZE_FORMAT" items",
173                         g_variant_iter_n_children(acquire));
174         __gv2c_array(acquire, &acquire_requests);
175
176         *priority_error = (gboolean *) g_malloc0_n(
177                         g_variant_iter_n_children(acquire), sizeof(**priority_error));
178
179         ret = _mmrm_dmn_commit(id, release_requests, acquire_requests);
180
181         for (i = 0; acquire_requests[i].type != MM_RESOURCE_MANAGER_NO_RES; i++)
182                 (*priority_error)[i] = acquire_requests[i].priority_error;
183
184         g_free(release_requests);
185         g_free(acquire_requests);
186
187         return ret;
188 }
189
190 int _mmrm_dmn_dbus_release_callback(mm_resource_manager_id id,
191                 mm_resource_manager_res_type_e type,
192                 mm_resource_manager_res_volume volume)
193 {
194         mmresource_manager_emit_release_callback(interface, id, type, volume);
195         return MM_RESOURCE_MANAGER_ERROR_NONE;
196 }
197
198 int _mmrm_dmn_dbus_status_callback(mm_resource_manager_status_e status)
199 {
200         MM_RM_DEBUG("Emitting %d status", status);
201         mmresource_manager_emit_status_callback(interface, status);
202         return MM_RESOURCE_MANAGER_ERROR_NONE;
203 }
204
205 void _mmrm_dmn_notify_fork_done(void)
206 {
207         /* Send "string" through the output side of pipe */
208         MM_RM_RETM_IF(write(notify_fd[1], MSG_DONE, strlen(MSG_DONE) + 1) < 0,
209                 "Failed to notify parent process that child initialization is done");
210
211         MM_RM_DEBUG("[%d] Notify parent process that child initialization is done", notify_fd[1]);
212         close(notify_fd[0]);
213         close(notify_fd[1]);
214 }
215
216 static void __gv2c_array(GVariantIter *gv, mm_resource_manager_dmn_res_request_s **c)
217 {
218         int i;
219         mm_resource_manager_dmn_res_request_s *rs;
220
221         rs = (mm_resource_manager_dmn_res_request_s *)
222                         g_malloc0_n(g_variant_iter_n_children(gv), sizeof(*rs));
223         for (i = 0; g_variant_iter_next(gv, "(ii)", &rs[i].type, &rs[i].volume); i++)
224                 MM_RM_DEBUG("(type,vol) = (%d,%d)", rs[i].type, rs[i].volume);
225
226         *c = rs;
227 }
228
229 static gboolean on_get_conf(MMResourceManager *interface,
230                 GDBusMethodInvocation *invocation, gpointer user_data)
231 {
232         int i, j;
233         gint error = 0;
234         mm_resource_manager_res_volume *max_volume = NULL;
235         mm_resource_manager_condition_volume_a *cond_volume = NULL;
236         GVariantBuilder *res_type_builder;
237         GVariantBuilder *res_cond_builder;
238         GVariant *res_type_conf;
239         GVariant *res_cond_conf;
240
241         error = _mmrm_dmn_dbus_get_conf(&max_volume, &cond_volume);
242
243         res_type_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
244         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
245                 g_variant_builder_add_value(res_type_builder, g_variant_new("i", max_volume[i]));
246
247         res_type_conf = g_variant_builder_end(res_type_builder);
248         g_variant_builder_unref(res_type_builder);
249
250         res_type_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
251         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
252                 res_cond_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
253                 for (j = 0; j < MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX; j++)
254                         g_variant_builder_add_value(res_cond_builder, g_variant_new("i", cond_volume[i][j]));
255
256                 g_variant_builder_add_value(res_type_builder, g_variant_builder_end(res_cond_builder));
257                 g_variant_builder_unref(res_cond_builder);
258         }
259         res_cond_conf = g_variant_builder_end(res_type_builder);
260         g_variant_builder_unref(res_type_builder);
261
262         mmresource_manager_complete_conf(interface, invocation, error, res_type_conf, res_cond_conf);
263
264         return TRUE;
265 }
266
267 static gboolean on_create_handle(MMResourceManager *interface,
268                 GDBusMethodInvocation *invocation, const gint app_class,
269                 gpointer user_data)
270 {
271         guint64 id = 0;
272         gint error = 0;
273
274         error = _mmrm_dmn_dbus_create(app_class, &id);
275
276         MM_RM_DEBUG("Receive create message for RM");
277
278         mmresource_manager_complete_create(interface, invocation, id, error);
279
280         return TRUE;
281 }
282
283 static gboolean on_destroy_handle(MMResourceManager *interface,
284                 GDBusMethodInvocation *invocation, const guint64 id, gpointer user_data)
285 {
286         gint error = 0;
287
288         MM_RM_DEBUG("Receive destroy message for RM");
289         error = _mmrm_dmn_dbus_destroy(id);
290
291         mmresource_manager_complete_destroy(interface, invocation, error);
292         return TRUE;
293 }
294
295 static gboolean on_commit_handle(MMResourceManager *interface,
296                 GDBusMethodInvocation *invocation, const guint64 id,
297                 GVariant *release, GVariant *acquire, gpointer user_data)
298 {
299         gint error = 0;
300         gboolean *flags;
301         GVariantBuilder *flags_builder;
302         GVariant *not_acquired_flags;
303         GVariantIter *release_array;
304         GVariantIter *acquire_array;
305         gsize acquire_len;
306         gint i;
307
308         MM_RM_DEBUG("Receive commit message");
309
310         release_array = g_variant_iter_new(release);
311         acquire_array = g_variant_iter_new(acquire);
312         acquire_len = g_variant_iter_n_children(acquire_array);
313
314         error = _mmrm_dmn_dbus_commit(id, release_array, acquire_array, &flags);
315
316         flags_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
317         for (i = 0; i < acquire_len; i++)
318                 g_variant_builder_add_value(flags_builder, g_variant_new("b", flags[i]));
319         not_acquired_flags = g_variant_builder_end(flags_builder);
320         mmresource_manager_complete_commit(interface, invocation, error, not_acquired_flags);
321
322         g_free(flags);
323         g_variant_builder_unref(flags_builder);
324         g_variant_iter_free(release_array);
325         g_variant_iter_free(acquire_array);
326
327         return TRUE;
328 }
329
330 static void on_bus_acquired(GDBusConnection *connection, const gchar *name,
331                 gpointer user_data)
332 {
333         GError* error = NULL;
334         MM_RM_DEBUG("name of bus = %s, userID = %d", name, getuid());
335
336         g_signal_connect(interface, "handle-conf", G_CALLBACK(on_get_conf), NULL);
337         g_signal_connect(interface, "handle-create", G_CALLBACK(on_create_handle), NULL);
338         g_signal_connect(interface, "handle-destroy", G_CALLBACK(on_destroy_handle), NULL);
339         g_signal_connect(interface, "handle-commit", G_CALLBACK(on_commit_handle), NULL);
340
341         if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(interface),
342                         connection, RMD_GDBUS_PATH, &error)) {
343                 MM_RM_ERROR("failed to export interface. msg : %s", error->message);
344                 g_error_free(error);
345                 return;
346         }
347
348         MM_RM_RETM_IF(!_create_daemon_setup_file(), "Daemon cannot create setup file");
349 }