Initialize Tizen 2.3
[framework/system/deviced.git] / src / core / edbus-handler.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdbool.h>
21 #include "core/log.h"
22 #include "core/data.h"
23 #include "core/edbus-handler.h"
24 #include "core/common.h"
25 #include "core/device-notifier.h"
26 #include "core/list.h"
27
28 #define EDBUS_INIT_RETRY_COUNT 5
29 #define NAME_OWNER_CHANGED "NameOwnerChanged"
30 #define NAME_OWNER_MATCH "type='signal',sender='org.freedesktop.DBus',\
31         path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',\
32         member='NameOwnerChanged',arg0='%s'"
33
34 /* -1 is a default timeout value, it's converted to 25*1000 internally. */
35 #define DBUS_REPLY_TIMEOUT      (-1)
36 #define RETRY_MAX 5
37
38 struct edbus_list{
39         char *signal_name;
40         E_DBus_Signal_Handler *handler;
41 };
42
43 static struct edbus_object {
44         const char *path;
45         const char *interface;
46         E_DBus_Object *obj;
47         E_DBus_Interface *iface;
48 } edbus_objects[] = {
49         { DEVICED_PATH_CORE   , DEVICED_INTERFACE_CORE   , NULL, NULL },
50         { DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY, NULL, NULL },
51         { DEVICED_PATH_PASS   , DEVICED_INTERFACE_PASS   , NULL, NULL },
52         { DEVICED_PATH_HALL   , DEVICED_INTERFACE_HALL   , NULL, NULL },
53         { DEVICED_PATH_POWER  , DEVICED_INTERFACE_POWER  , NULL, NULL },
54         { DEVICED_PATH_STORAGE, DEVICED_INTERFACE_STORAGE, NULL, NULL },
55         { DEVICED_PATH_HAPTIC , DEVICED_INTERFACE_HAPTIC , NULL, NULL },
56         { DEVICED_PATH_LED    , DEVICED_INTERFACE_LED    , NULL, NULL },
57         { DEVICED_PATH_MMC    , DEVICED_INTERFACE_MMC    , NULL, NULL },
58         { DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS, NULL, NULL },
59         { DEVICED_PATH_KEY    , DEVICED_INTERFACE_KEY    , NULL, NULL },
60         { DEVICED_PATH_CPU    , DEVICED_INTERFACE_CPU    , NULL, NULL },
61         { DEVICED_PATH_PMQOS  , DEVICED_INTERFACE_PMQOS  , NULL, NULL },
62         { DEVICED_PATH_SYSNOTI, DEVICED_INTERFACE_SYSNOTI, NULL, NULL },
63         { DEVICED_PATH_USBHOST, DEVICED_INTERFACE_USBHOST, NULL, NULL },
64         { DEVICED_PATH_EXTCON , DEVICED_INTERFACE_EXTCON , NULL, NULL },
65         { DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY, NULL, NULL },
66         { DEVICED_PATH_BOARD, DEVICED_INTERFACE_BOARD, NULL, NULL },
67         { DEVICED_PATH_TESTMODE, DEVICED_INTERFACE_TESTMODE, NULL, NULL},
68         /* Add new object & interface here*/
69 };
70
71 static dd_list *edbus_handler_list;
72 static dd_list *edbus_watch_list;
73 static int edbus_init_val;
74 static DBusConnection *conn;
75 static E_DBus_Connection *edbus_conn;
76 static DBusPendingCall *edbus_request_name;
77
78 static int register_edbus_interface(struct edbus_object *object)
79 {
80         int ret;
81
82         if (!object) {
83                 _E("object is invalid value!");
84                 return -1;
85         }
86
87         object->obj = e_dbus_object_add(edbus_conn, object->path, NULL);
88         if (!object->obj) {
89                 _E("fail to add edbus obj");
90                 return -1;
91         }
92
93         object->iface = e_dbus_interface_new(object->interface);
94         if (!object->iface) {
95                 _E("fail to add edbus interface");
96                 return -1;
97         }
98
99         e_dbus_object_interface_attach(object->obj, object->iface);
100
101         return 0;
102 }
103
104 E_DBus_Interface *get_edbus_interface(const char *path)
105 {
106         int i;
107
108         for (i = 0; i < ARRAY_SIZE(edbus_objects); i++)
109                 if (!strcmp(path, edbus_objects[i].path))
110                         return edbus_objects[i].iface;
111
112         return NULL;
113 }
114
115 pid_t get_edbus_sender_pid(DBusMessage *msg)
116 {
117         const char *sender;
118         DBusMessage *send_msg;
119         DBusPendingCall *pending;
120         DBusMessageIter iter;
121         int ret;
122         pid_t pid;
123
124         if (!msg) {
125                 _E("invalid argument!");
126                 return -1;
127         }
128
129         sender = dbus_message_get_sender(msg);
130         if (!sender) {
131                 _E("invalid sender!");
132                 return -1;
133         }
134
135         send_msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
136                                     DBUS_PATH_DBUS,
137                                     DBUS_INTERFACE_DBUS,
138                                     "GetConnectionUnixProcessID");
139         if (!send_msg) {
140                 _E("invalid send msg!");
141                 return -1;
142         }
143
144         ret = dbus_message_append_args(send_msg, DBUS_TYPE_STRING,
145                                     &sender, DBUS_TYPE_INVALID);
146         if (!ret) {
147                 _E("fail to append args!");
148                 dbus_message_unref(send_msg);
149                 return -1;
150         }
151
152         pending = e_dbus_message_send(edbus_conn, send_msg, NULL, -1, NULL);
153         if (!pending) {
154                 _E("pending is null!");
155                 dbus_message_unref(send_msg);
156                 return -1;
157         }
158
159         dbus_message_unref(send_msg);
160
161         /* block until reply is received */
162         dbus_pending_call_block(pending);
163
164         msg = dbus_pending_call_steal_reply(pending);
165         dbus_pending_call_unref(pending);
166         if (!msg) {
167                 _E("reply msg is null!");
168                 return -1;
169         }
170
171         dbus_message_iter_init(msg, &iter);
172         dbus_message_iter_get_basic(&iter, &pid);
173         dbus_message_unref(msg);
174
175         return pid;
176 }
177
178 static void unregister_edbus_signal_handle(void)
179 {
180         dd_list *tmp;
181         struct edbus_list *entry;
182
183         DD_LIST_FOREACH(edbus_handler_list, tmp, entry) {
184                 e_dbus_signal_handler_del(edbus_conn, entry->handler);
185                 DD_LIST_REMOVE(edbus_handler_list, entry);
186                 free(entry->signal_name);
187                 free(entry);
188         }
189 }
190
191 int register_edbus_signal_handler(const char *path, const char *interface,
192                 const char *name, E_DBus_Signal_Cb cb)
193 {
194         dd_list *tmp;
195         struct edbus_list *entry;
196         E_DBus_Signal_Handler *handler;
197
198         DD_LIST_FOREACH(edbus_handler_list, tmp, entry) {
199                 if (strncmp(entry->signal_name, name, strlen(name)) == 0)
200                         return -EEXIST;
201         }
202
203         handler = e_dbus_signal_handler_add(edbus_conn, NULL, path,
204                                 interface, name, cb, NULL);
205
206         if (!handler) {
207                 _E("fail to add edbus handler");
208                 return -ENOMEM;
209         }
210
211         entry = malloc(sizeof(struct edbus_list));
212
213         if (!entry) {
214                 _E("Malloc failed");
215                 return -ENOMEM;
216         }
217
218         entry->signal_name = strndup(name, strlen(name));
219
220         if (!entry->signal_name) {
221                 _E("Malloc failed");
222                 free(entry);
223                 return -ENOMEM;
224         }
225
226         entry->handler = handler;
227         DD_LIST_PREPEND(edbus_handler_list, entry);
228         if (!edbus_handler_list) {
229                 _E("eina_list_prepend failed");
230                 free(entry->signal_name);
231                 free(entry);
232                 return -ENOMEM;
233         }
234         return 0;
235 }
236
237 int broadcast_edbus_signal(const char *path, const char *interface,
238                 const char *name, const char *sig, char *param[])
239 {
240         DBusMessage *msg;
241         DBusMessageIter iter;
242         int r;
243
244         msg = dbus_message_new_signal(path, interface, name);
245         if (!msg) {
246                 _E("fail to allocate new %s.%s signal", interface, name);
247                 return -EPERM;
248         }
249
250         dbus_message_iter_init_append(msg, &iter);
251         r = append_variant(&iter, sig, param);
252         if (r < 0) {
253                 _E("append_variant error(%d)", r);
254                 return -EPERM;
255         }
256
257         e_dbus_message_send(edbus_conn, msg, NULL, -1, NULL);
258
259         dbus_message_unref(msg);
260         return 0;
261 }
262
263 static DBusHandlerResult message_filter(DBusConnection *connection,
264                 DBusMessage *message, void *data)
265 {
266         char match[256];
267         int ret;
268         const char *iface, *member, *arg = NULL;
269         struct watch *watch;
270         dd_list *n;
271
272         if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
273                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
274
275         iface = dbus_message_get_interface(message);
276         member = dbus_message_get_member(message);
277
278         if (strcmp(iface, DBUS_INTERFACE_DBUS))
279                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
280
281         if (strcmp(member, NAME_OWNER_CHANGED))
282                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
283
284         ret = dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
285                     DBUS_TYPE_INVALID);
286         if (!ret) {
287                 _E("no message");
288                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
289         }
290
291         _D("Argument : %s", arg);
292
293         DD_LIST_FOREACH(edbus_watch_list, n, watch) {
294                 if (strcmp(arg, watch->name)) continue;
295
296                 if (watch->func)
297                         watch->func(watch->name, watch->id);
298
299                 DD_LIST_REMOVE(edbus_watch_list, watch);
300                 free(watch->name);
301                 free(watch);
302         }
303
304         /* remove registered sender */
305         snprintf(match, sizeof(match), NAME_OWNER_MATCH, arg);
306         dbus_bus_remove_match(conn, match, NULL);
307
308
309         if (DD_LIST_LENGTH(edbus_watch_list) == 0) {
310                 dbus_connection_remove_filter(conn, message_filter, NULL);
311                 _I("remove message filter, no watcher!");
312         }
313
314         return DBUS_HANDLER_RESULT_HANDLED;
315 }
316
317 int register_edbus_watch(DBusMessage *msg, enum watch_id id, int (*func)(char *name, enum watch_id id))
318 {
319         char match[256];
320         const char *sender;
321         struct watch *watch;
322         dd_list *n;
323         int ret;
324         bool matched = false;
325
326         if (!msg) {
327                 _E("invalid argument!");
328                 return -EINVAL;
329         }
330
331         sender = dbus_message_get_sender(msg);
332         if (!sender) {
333                 _E("invalid sender!");
334                 return -EINVAL;
335         }
336
337         /* check the sender&id is already registered */
338         DD_LIST_FOREACH(edbus_watch_list, n, watch) {
339                 if (strcmp(sender, watch->name))
340                         continue;
341                 if (id != watch->id) {
342                         matched = true;
343                         continue;
344                 }
345
346                 _I("%s(%d) is already watched!", watch->name, watch->id);
347
348                 return 0;
349         }
350
351         watch = malloc(sizeof(struct watch));
352         if (!watch) {
353                 _E("Fail to malloc for watch!");
354                 return -ENOMEM;
355         }
356
357         watch->id = id;
358         watch->func = func;
359         watch->name = strndup(sender, strlen(sender));
360
361         if (!watch->name) {
362                 _E("Fail to malloc for watch name");
363                 free(watch);
364                 return -ENOMEM;
365         }
366
367         /* Add message filter */
368         if (DD_LIST_LENGTH(edbus_watch_list) == 0) {
369                 ret = dbus_connection_add_filter(conn, message_filter, NULL, NULL);
370                 if (!ret) {
371                         _E("fail to add message filter!");
372                         free(watch->name);
373                         free(watch);
374                         return -ENOMEM;
375                 }
376                 _I("success to add message filter!");
377         }
378
379         /* Add watch to watch list */
380         DD_LIST_APPEND(edbus_watch_list, watch);
381
382         if (!matched) {
383                 snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch->name);
384                 dbus_bus_add_match(conn, match, NULL);
385         }
386
387         _I("%s(%d) is watched by dbus!", watch->name, watch->id);
388
389         return 0;
390 }
391
392 int unregister_edbus_watch(DBusMessage *msg, enum watch_id id)
393 {
394         char match[256];
395         const char *sender;
396         struct watch *watch;
397         dd_list *n;
398         bool matched = false;
399
400         if (!msg) {
401                 _E("invalid argument!");
402                 return -EINVAL;
403         }
404
405         sender = dbus_message_get_sender(msg);
406         if (!sender) {
407                 _E("invalid sender!");
408                 return -EINVAL;
409         }
410
411         DD_LIST_FOREACH(edbus_watch_list, n, watch) {
412                 if (strcmp(sender, watch->name))
413                         continue;
414
415                 if (id != watch->id) {
416                         matched = true;
417                         continue;
418                 }
419                 DD_LIST_REMOVE(edbus_watch_list, watch);
420                 free(watch->name);
421                 free(watch);
422         }
423
424         /* remove match */
425         if (!matched) {
426                 snprintf(match, sizeof(match), NAME_OWNER_MATCH, sender);
427                 dbus_bus_remove_match(conn, match, NULL);
428
429                 if (DD_LIST_LENGTH(edbus_watch_list) == 0)
430                         dbus_connection_remove_filter(conn, message_filter,
431                             NULL);
432         }
433
434         return 0;
435 }
436
437 static void unregister_edbus_watch_all(void)
438 {
439         char match[256];
440         dd_list *n;
441         struct watch *watch;
442
443         if (DD_LIST_LENGTH(edbus_watch_list) > 0)
444                 dbus_connection_remove_filter(conn, message_filter, NULL);
445
446         DD_LIST_FOREACH(edbus_watch_list, n, watch) {
447                 snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch->name);
448                 dbus_bus_remove_match(conn, match, NULL);
449                 DD_LIST_REMOVE(edbus_watch_list, watch);
450                 free(watch->name);
451                 free(watch);
452         }
453 }
454
455 int register_edbus_method(const char *path, const struct edbus_method *edbus_methods, int size)
456 {
457         E_DBus_Interface *iface;
458         int ret;
459         int i;
460
461         iface = get_edbus_interface(path);
462
463         if (!iface) {
464                 _E("fail to get edbus interface!");
465                 return -ENODEV;
466         }
467
468         for (i = 0; i < size; i++) {
469                 ret = e_dbus_interface_method_add(iface,
470                                     edbus_methods[i].member,
471                                     edbus_methods[i].signature,
472                                     edbus_methods[i].reply_signature,
473                                     edbus_methods[i].func);
474                 if (!ret) {
475                         _E("fail to add method %s!", edbus_methods[i].member);
476                         return -EINVAL;
477                 }
478         }
479
480         return 0;
481 }
482
483 static void request_name_cb(void *data, DBusMessage *msg, DBusError *error)
484 {
485         DBusError err;
486         unsigned int val;
487         int r;
488
489         if (!msg) {
490                 _D("invalid DBusMessage!");
491                 return;
492         }
493
494         dbus_error_init(&err);
495         r = dbus_message_get_args(msg, &err, DBUS_TYPE_UINT32, &val, DBUS_TYPE_INVALID);
496         if (!r) {
497                 _E("no message : [%s:%s]", err.name, err.message);
498                 dbus_error_free(&err);
499                 return;
500         }
501
502         _I("Request Name reply : %d", val);
503 }
504
505 void edbus_init(void *data)
506 {
507         DBusError error;
508         int retry = 0;
509         int i, ret;
510
511         dbus_threads_init_default();
512         dbus_error_init(&error);
513
514         do {
515                 edbus_init_val = e_dbus_init();
516                 if (edbus_init_val)
517                         break;
518                 if (retry == EDBUS_INIT_RETRY_COUNT) {
519                         _E("fail to init edbus");
520                         return;
521                 }
522                 retry++;
523         } while (retry <= EDBUS_INIT_RETRY_COUNT);
524
525         retry = 0;
526         do {
527                 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
528                 if (conn)
529                         break;
530                 if (retry == EDBUS_INIT_RETRY_COUNT) {
531                         _E("fail to get dbus");
532                         goto out1;
533                 }
534                 retry++;
535         } while (retry <= EDBUS_INIT_RETRY_COUNT);
536
537         retry = 0;
538         do {
539                 edbus_conn = e_dbus_connection_setup(conn);
540                 if (edbus_conn)
541                         break;
542                 if (retry == EDBUS_INIT_RETRY_COUNT) {
543                         _E("fail to get edbus");
544                         goto out2;
545                 }
546                 retry++;
547         } while (retry <= EDBUS_INIT_RETRY_COUNT);
548
549         retry = 0;
550         do {
551                 edbus_request_name = e_dbus_request_name(edbus_conn, DEVICED_BUS_NAME,
552                                 DBUS_NAME_FLAG_REPLACE_EXISTING, request_name_cb, NULL);
553                 if (edbus_request_name)
554                         break;
555                 if (retry == EDBUS_INIT_RETRY_COUNT) {
556                         _E("fail to request edbus name");
557                         goto out3;
558                 }
559                 retry++;
560         } while (retry <= EDBUS_INIT_RETRY_COUNT);
561
562         for (i = 0; i < ARRAY_SIZE(edbus_objects); i++) {
563                 ret = register_edbus_interface(&edbus_objects[i]);
564                 if (ret < 0) {
565                         _E("fail to add obj & interface for %s",
566                                     edbus_objects[i].interface);
567                         return;
568                 }
569                 _D("add new obj for %s", edbus_objects[i].interface);
570         }
571         return;
572
573 out3:
574         e_dbus_connection_close(edbus_conn);
575 out2:
576         dbus_connection_set_exit_on_disconnect(conn, FALSE);
577 out1:
578         e_dbus_shutdown();
579 }
580
581 void edbus_exit(void *data)
582 {
583         unregister_edbus_signal_handle();
584         unregister_edbus_watch_all();
585         e_dbus_connection_close(edbus_conn);
586         e_dbus_shutdown();
587 }