tizen 2.3 release
[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/edbus-handler.h"
23 #include "core/common.h"
24 #include "core/device-notifier.h"
25 #include "core/list.h"
26
27 #define EDBUS_INIT_RETRY_COUNT 5
28 #define NAME_OWNER_CHANGED "NameOwnerChanged"
29 #define NAME_OWNER_MATCH "type='signal',sender='org.freedesktop.DBus',\
30         path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',\
31         member='NameOwnerChanged',arg0='%s'"
32
33 /* -1 is a default timeout value, it's converted to 25*1000 internally. */
34 #define DBUS_REPLY_TIMEOUT      (-1)
35 #define RETRY_MAX 5
36
37 struct edbus_list{
38         char *signal_name;
39         E_DBus_Signal_Handler *handler;
40 };
41
42 static struct edbus_object {
43         const char *path;
44         const char *interface;
45         E_DBus_Object *obj;
46         E_DBus_Interface *iface;
47 } edbus_objects[] = {
48         { DEVICED_PATH_CORE   , DEVICED_INTERFACE_CORE   , NULL, NULL },
49         { DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY, NULL, NULL },
50         { DEVICED_PATH_PASS   , DEVICED_INTERFACE_PASS   , NULL, NULL },
51         { DEVICED_PATH_HALL   , DEVICED_INTERFACE_HALL   , NULL, NULL },
52         { DEVICED_PATH_POWER  , DEVICED_INTERFACE_POWER  , NULL, NULL },
53         { DEVICED_PATH_STORAGE, DEVICED_INTERFACE_STORAGE, NULL, NULL },
54         { DEVICED_PATH_HAPTIC , DEVICED_INTERFACE_HAPTIC , NULL, NULL },
55         { DEVICED_PATH_LED    , DEVICED_INTERFACE_LED    , NULL, NULL },
56         { DEVICED_PATH_MMC    , DEVICED_INTERFACE_MMC    , NULL, NULL },
57         { DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS, NULL, NULL },
58         { DEVICED_PATH_KEY    , DEVICED_INTERFACE_KEY    , NULL, NULL },
59         { DEVICED_PATH_CPU    , DEVICED_INTERFACE_CPU    , NULL, NULL },
60         { DEVICED_PATH_PMQOS  , DEVICED_INTERFACE_PMQOS  , NULL, NULL },
61         { DEVICED_PATH_SYSNOTI, DEVICED_INTERFACE_SYSNOTI, NULL, NULL },
62         { DEVICED_PATH_USB    , DEVICED_INTERFACE_USB    , 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         { DEVICED_PATH_APPS, DEVICED_INTERFACE_APPS, NULL, NULL},
69         { DEVICED_PATH_GPIO, DEVICED_INTERFACE_GPIO, NULL, NULL},
70         { DEVICED_PATH_HDMICEC, DEVICED_INTERFACE_HDMICEC, NULL, NULL},
71         /* Add new object & interface here*/
72 };
73
74 static dd_list *edbus_owner_list;
75 static dd_list *edbus_handler_list;
76 static dd_list *edbus_watch_list;
77 static int edbus_init_val;
78 static DBusConnection *conn;
79 static E_DBus_Connection *edbus_conn;
80 static DBusPendingCall *edbus_request_name;
81
82 static int register_edbus_interface(struct edbus_object *object)
83 {
84         int ret;
85
86         if (!object) {
87                 _E("object is invalid value!");
88                 return -1;
89         }
90
91         object->obj = e_dbus_object_add(edbus_conn, object->path, NULL);
92         if (!object->obj) {
93                 _E("fail to add edbus obj");
94                 return -1;
95         }
96
97         object->iface = e_dbus_interface_new(object->interface);
98         if (!object->iface) {
99                 _E("fail to add edbus interface");
100                 return -1;
101         }
102
103         e_dbus_object_interface_attach(object->obj, object->iface);
104
105         return 0;
106 }
107
108 E_DBus_Interface *get_edbus_interface(const char *path)
109 {
110         int i;
111
112         for (i = 0; i < ARRAY_SIZE(edbus_objects); i++)
113                 if (!strcmp(path, edbus_objects[i].path))
114                         return edbus_objects[i].iface;
115
116         return NULL;
117 }
118
119 pid_t get_edbus_sender_pid(DBusMessage *msg)
120 {
121         const char *sender;
122         DBusMessage *send_msg;
123         DBusPendingCall *pending;
124         DBusMessageIter iter;
125         int ret;
126         pid_t pid;
127
128         if (!msg) {
129                 _E("invalid argument!");
130                 return -1;
131         }
132
133         sender = dbus_message_get_sender(msg);
134         if (!sender) {
135                 _E("invalid sender!");
136                 return -1;
137         }
138
139         send_msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
140                                     DBUS_PATH_DBUS,
141                                     DBUS_INTERFACE_DBUS,
142                                     "GetConnectionUnixProcessID");
143         if (!send_msg) {
144                 _E("invalid send msg!");
145                 return -1;
146         }
147
148         ret = dbus_message_append_args(send_msg, DBUS_TYPE_STRING,
149                                     &sender, DBUS_TYPE_INVALID);
150         if (!ret) {
151                 _E("fail to append args!");
152                 dbus_message_unref(send_msg);
153                 return -1;
154         }
155
156         pending = e_dbus_message_send(edbus_conn, send_msg, NULL, -1, NULL);
157         if (!pending) {
158                 _E("pending is null!");
159                 dbus_message_unref(send_msg);
160                 return -1;
161         }
162
163         dbus_message_unref(send_msg);
164
165         /* block until reply is received */
166         dbus_pending_call_block(pending);
167
168         msg = dbus_pending_call_steal_reply(pending);
169         dbus_pending_call_unref(pending);
170         if (!msg) {
171                 _E("reply msg is null!");
172                 return -1;
173         }
174
175         dbus_message_iter_init(msg, &iter);
176         dbus_message_iter_get_basic(&iter, &pid);
177         dbus_message_unref(msg);
178
179         return pid;
180 }
181
182 static void unregister_edbus_signal_handle(void)
183 {
184         dd_list *tmp;
185         struct edbus_list *entry;
186
187         DD_LIST_FOREACH(edbus_handler_list, tmp, entry) {
188                 e_dbus_signal_handler_del(edbus_conn, entry->handler);
189                 DD_LIST_REMOVE(edbus_handler_list, entry);
190                 free(entry->signal_name);
191                 free(entry);
192         }
193 }
194
195 int register_edbus_signal_handler(const char *path, const char *interface,
196                 const char *name, E_DBus_Signal_Cb cb)
197 {
198         dd_list *tmp;
199         struct edbus_list *entry;
200         E_DBus_Signal_Handler *handler;
201
202         DD_LIST_FOREACH(edbus_handler_list, tmp, entry) {
203                 if (strncmp(entry->signal_name, name, strlen(name)) == 0)
204                         return -EEXIST;
205         }
206
207         handler = e_dbus_signal_handler_add(edbus_conn, NULL, path,
208                                 interface, name, cb, NULL);
209
210         if (!handler) {
211                 _E("fail to add edbus handler");
212                 return -ENOMEM;
213         }
214
215         entry = malloc(sizeof(struct edbus_list));
216
217         if (!entry) {
218                 _E("Malloc failed");
219                 return -ENOMEM;
220         }
221
222         entry->signal_name = strndup(name, strlen(name));
223
224         if (!entry->signal_name) {
225                 _E("Malloc failed");
226                 free(entry);
227                 return -ENOMEM;
228         }
229
230         entry->handler = handler;
231         DD_LIST_PREPEND(edbus_handler_list, entry);
232         if (!edbus_handler_list) {
233                 _E("eina_list_prepend failed");
234                 free(entry->signal_name);
235                 free(entry);
236                 return -ENOMEM;
237         }
238         return 0;
239 }
240
241 int broadcast_edbus_signal(const char *path, const char *interface,
242                 const char *name, const char *sig, char *param[])
243 {
244         DBusMessage *msg;
245         DBusMessageIter iter;
246         int r;
247
248         msg = dbus_message_new_signal(path, interface, name);
249         if (!msg) {
250                 _E("fail to allocate new %s.%s signal", interface, name);
251                 return -EPERM;
252         }
253
254         dbus_message_iter_init_append(msg, &iter);
255         r = append_variant(&iter, sig, param);
256         if (r < 0) {
257                 _E("append_variant error(%d)", r);
258                 return -EPERM;
259         }
260
261         r = dbus_connection_send(conn, msg, NULL);
262         dbus_message_unref(msg);
263
264         if (r != TRUE) {
265                 _E("dbus_connection_send error(%s:%s-%s)",
266                     path, interface, name);
267                 return -ECOMM;
268         }
269
270         return 0;
271 }
272
273 static DBusHandlerResult message_filter(DBusConnection *connection,
274                 DBusMessage *message, void *data)
275 {
276         char match[256];
277         int ret;
278         const char *iface, *member, *arg = NULL;
279         struct watch *watch;
280         dd_list *n;
281
282         if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
283                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
284
285         iface = dbus_message_get_interface(message);
286         member = dbus_message_get_member(message);
287
288         if (strcmp(iface, DBUS_INTERFACE_DBUS))
289                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
290
291         if (strcmp(member, NAME_OWNER_CHANGED))
292                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
293
294         ret = dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
295                     DBUS_TYPE_INVALID);
296         if (!ret) {
297                 _E("no message");
298                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
299         }
300
301         _D("Argument : %s", arg);
302
303         DD_LIST_FOREACH(edbus_watch_list, n, watch) {
304                 if (strcmp(arg, watch->name)) continue;
305
306                 if (watch->func)
307                         watch->func(watch->name, watch->id);
308
309                 DD_LIST_REMOVE(edbus_watch_list, watch);
310                 free(watch->name);
311                 free(watch);
312         }
313
314         /* remove registered sender */
315         snprintf(match, sizeof(match), NAME_OWNER_MATCH, arg);
316         dbus_bus_remove_match(conn, match, NULL);
317
318
319         if (DD_LIST_LENGTH(edbus_watch_list) == 0) {
320                 dbus_connection_remove_filter(conn, message_filter, NULL);
321                 _I("remove message filter, no watcher!");
322         }
323
324         return DBUS_HANDLER_RESULT_HANDLED;
325 }
326
327 int register_edbus_watch(DBusMessage *msg, enum watch_id id, int (*func)(char *name, enum watch_id id))
328 {
329         char match[256];
330         const char *sender;
331         struct watch *watch;
332         dd_list *n;
333         int ret;
334         bool matched = false;
335
336         if (!msg) {
337                 _E("invalid argument!");
338                 return -EINVAL;
339         }
340
341         sender = dbus_message_get_sender(msg);
342         if (!sender) {
343                 _E("invalid sender!");
344                 return -EINVAL;
345         }
346
347         /* check the sender&id is already registered */
348         DD_LIST_FOREACH(edbus_watch_list, n, watch) {
349                 if (strcmp(sender, watch->name))
350                         continue;
351                 if (id != watch->id) {
352                         matched = true;
353                         continue;
354                 }
355
356                 _I("%s(%d) is already watched!", watch->name, watch->id);
357
358                 return 0;
359         }
360
361         watch = malloc(sizeof(struct watch));
362         if (!watch) {
363                 _E("Fail to malloc for watch!");
364                 return -ENOMEM;
365         }
366
367         watch->id = id;
368         watch->func = func;
369         watch->name = strndup(sender, strlen(sender));
370
371         if (!watch->name) {
372                 _E("Fail to malloc for watch name");
373                 free(watch);
374                 return -ENOMEM;
375         }
376
377         /* Add message filter */
378         if (DD_LIST_LENGTH(edbus_watch_list) == 0) {
379                 ret = dbus_connection_add_filter(conn, message_filter, NULL, NULL);
380                 if (!ret) {
381                         _E("fail to add message filter!");
382                         free(watch->name);
383                         free(watch);
384                         return -ENOMEM;
385                 }
386                 _I("success to add message filter!");
387         }
388
389         /* Add watch to watch list */
390         DD_LIST_APPEND(edbus_watch_list, watch);
391
392         if (!matched) {
393                 snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch->name);
394                 dbus_bus_add_match(conn, match, NULL);
395         }
396
397         _I("%s(%d) is watched by dbus!", watch->name, watch->id);
398
399         return 0;
400 }
401
402 int unregister_edbus_watch(DBusMessage *msg, enum watch_id id)
403 {
404         char match[256];
405         const char *sender;
406         struct watch *watch;
407         dd_list *n;
408         bool matched = false;
409
410         if (!msg) {
411                 _E("invalid argument!");
412                 return -EINVAL;
413         }
414
415         sender = dbus_message_get_sender(msg);
416         if (!sender) {
417                 _E("invalid sender!");
418                 return -EINVAL;
419         }
420
421         DD_LIST_FOREACH(edbus_watch_list, n, watch) {
422                 if (strcmp(sender, watch->name))
423                         continue;
424
425                 if (id != watch->id) {
426                         matched = true;
427                         continue;
428                 }
429                 DD_LIST_REMOVE(edbus_watch_list, watch);
430                 free(watch->name);
431                 free(watch);
432         }
433
434         /* remove match */
435         if (!matched) {
436                 snprintf(match, sizeof(match), NAME_OWNER_MATCH, sender);
437                 dbus_bus_remove_match(conn, match, NULL);
438
439                 if (DD_LIST_LENGTH(edbus_watch_list) == 0)
440                         dbus_connection_remove_filter(conn, message_filter,
441                             NULL);
442         }
443
444         return 0;
445 }
446
447 static void unregister_edbus_watch_all(void)
448 {
449         char match[256];
450         dd_list *n;
451         struct watch *watch;
452
453         if (DD_LIST_LENGTH(edbus_watch_list) > 0)
454                 dbus_connection_remove_filter(conn, message_filter, NULL);
455
456         DD_LIST_FOREACH(edbus_watch_list, n, watch) {
457                 snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch->name);
458                 dbus_bus_remove_match(conn, match, NULL);
459                 DD_LIST_REMOVE(edbus_watch_list, watch);
460                 free(watch->name);
461                 free(watch);
462         }
463 }
464
465 int register_edbus_method(const char *path, const struct edbus_method *edbus_methods, int size)
466 {
467         E_DBus_Interface *iface;
468         int ret;
469         int i;
470
471         iface = get_edbus_interface(path);
472
473         if (!iface) {
474                 _E("fail to get edbus interface!");
475                 return -ENODEV;
476         }
477
478         for (i = 0; i < size; i++) {
479                 ret = e_dbus_interface_method_add(iface,
480                                     edbus_methods[i].member,
481                                     edbus_methods[i].signature,
482                                     edbus_methods[i].reply_signature,
483                                     edbus_methods[i].func);
484                 if (!ret) {
485                         _E("fail to add method %s!", edbus_methods[i].member);
486                         return -EINVAL;
487                 }
488         }
489
490         return 0;
491 }
492
493 static void request_name_cb(void *data, DBusMessage *msg, DBusError *error)
494 {
495         DBusError err;
496         unsigned int val;
497         int r;
498
499         if (!msg) {
500                 _D("invalid DBusMessage!");
501                 return;
502         }
503
504         dbus_error_init(&err);
505         r = dbus_message_get_args(msg, &err, DBUS_TYPE_UINT32, &val, DBUS_TYPE_INVALID);
506         if (!r) {
507                 _E("no message : [%s:%s]", err.name, err.message);
508                 dbus_error_free(&err);
509                 return;
510         }
511
512         _I("Request Name reply : %d", val);
513 }
514
515 static void check_owner_name(void)
516 {
517         DBusError err;
518         DBusMessage *msg;
519         DBusMessageIter iter;
520         char *pa[1];
521         char exe_name[PATH_MAX];
522         char *entry;
523         dd_list *n;
524         int pid;
525
526         DD_LIST_FOREACH(edbus_owner_list, n, entry) {
527                 pa[0] = entry;
528                 msg = dbus_method_sync_with_reply(E_DBUS_FDO_BUS,
529                         E_DBUS_FDO_PATH,
530                         E_DBUS_FDO_INTERFACE,
531                         "GetConnectionUnixProcessID", "s", pa);
532
533                 if (!msg) {
534                         _E("invalid DBusMessage!");
535                         return;
536                 }
537
538                 dbus_error_init(&err);
539                 dbus_message_iter_init(msg, &iter);
540
541                 dbus_message_iter_get_basic(&iter, &pid);
542                 if (get_cmdline_name(pid, exe_name, PATH_MAX) != 0)
543                         goto out;
544                 _I("%s(%d)", exe_name, pid);
545
546 out:
547                 dbus_message_unref(msg);
548                 dbus_error_free(&err);
549         }
550 }
551
552 static void check_owner_list(void)
553 {
554         DBusError err;
555         DBusMessage *msg;
556         DBusMessageIter array, iter, item, iter_val;
557         char *pa[1];
558         char *name;
559         char *entry;
560
561         pa[0] = DEVICED_BUS_NAME;
562         msg = dbus_method_sync_with_reply(E_DBUS_FDO_BUS,
563                         E_DBUS_FDO_PATH,
564                         E_DBUS_FDO_INTERFACE,
565                         "ListQueuedOwners", "s", pa);
566
567         if (!msg) {
568                 _E("invalid DBusMessage!");
569                 return;
570         }
571
572         dbus_error_init(&err);
573         dbus_message_iter_init(msg, &array);
574
575         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
576                 goto out;
577         dbus_message_iter_recurse(&array, &item);
578         while (dbus_message_iter_get_arg_type(&item) == DBUS_TYPE_STRING) {
579                 dbus_message_iter_get_basic(&item, &name);
580                 entry = strndup(name, strlen(name));
581                 DD_LIST_APPEND(edbus_owner_list, entry);
582                 if (!edbus_owner_list) {
583                         _E("append failed");
584                         free(entry);
585                         goto out;
586                 }
587                 dbus_message_iter_next(&item);
588         }
589
590 out:
591         dbus_message_unref(msg);
592         dbus_error_free(&err);
593 }
594
595 void edbus_init(void *data)
596 {
597         DBusError error;
598         int retry = 0;
599         int i, ret;
600
601         dbus_threads_init_default();
602         dbus_error_init(&error);
603
604         do {
605                 edbus_init_val = e_dbus_init();
606                 if (edbus_init_val)
607                         break;
608                 if (retry == EDBUS_INIT_RETRY_COUNT) {
609                         _E("fail to init edbus");
610                         return;
611                 }
612                 retry++;
613         } while (retry <= EDBUS_INIT_RETRY_COUNT);
614
615         retry = 0;
616         do {
617                 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
618                 if (conn)
619                         break;
620                 if (retry == EDBUS_INIT_RETRY_COUNT) {
621                         _E("fail to get dbus");
622                         goto out1;
623                 }
624                 retry++;
625         } while (retry <= EDBUS_INIT_RETRY_COUNT);
626
627         retry = 0;
628         do {
629                 edbus_conn = e_dbus_connection_setup(conn);
630                 if (edbus_conn)
631                         break;
632                 if (retry == EDBUS_INIT_RETRY_COUNT) {
633                         _E("fail to get edbus");
634                         goto out2;
635                 }
636                 retry++;
637         } while (retry <= EDBUS_INIT_RETRY_COUNT);
638
639         retry = 0;
640         do {
641                 edbus_request_name = e_dbus_request_name(edbus_conn, DEVICED_BUS_NAME,
642                                 DBUS_NAME_FLAG_REPLACE_EXISTING, request_name_cb, NULL);
643                 if (edbus_request_name)
644                         break;
645                 if (retry == EDBUS_INIT_RETRY_COUNT) {
646                         _E("fail to request edbus name");
647                         goto out3;
648                 }
649                 retry++;
650         } while (retry <= EDBUS_INIT_RETRY_COUNT);
651
652         for (i = 0; i < ARRAY_SIZE(edbus_objects); i++) {
653                 ret = register_edbus_interface(&edbus_objects[i]);
654                 if (ret < 0) {
655                         _E("fail to add obj & interface for %s",
656                                     edbus_objects[i].interface);
657                         return;
658                 }
659                 _D("add new obj for %s", edbus_objects[i].interface);
660         }
661         check_owner_list();
662         check_owner_name();
663         return;
664
665 out3:
666         e_dbus_connection_close(edbus_conn);
667 out2:
668         dbus_connection_set_exit_on_disconnect(conn, FALSE);
669 out1:
670         e_dbus_shutdown();
671 }
672
673 void edbus_exit(void *data)
674 {
675         unregister_edbus_signal_handle();
676         unregister_edbus_watch_all();
677         e_dbus_connection_close(edbus_conn);
678         e_dbus_shutdown();
679 }