Improve coverage
[platform/core/appfw/data-provider-master.git] / src / service_common.c
1 /*
2  * Copyright 2016  Samsung Electronics Co., Ltd
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 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <gio/gio.h>
20 #include <dlog.h>
21 #include <notification_setting.h>
22 #include <notification_setting_internal.h>
23 #include <notification_setting_service.h>
24 #include <notification_noti.h>
25 #include <badge_setting.h>
26 #include <badge_setting_service.h>
27 #include <badge_db.h>
28 #include <package-manager.h>
29 #include <tzplatform_config.h>
30 #include <pkgmgr-info.h>
31
32 #include "debug.h"
33 #include "pkgmgr.h"
34 #include "service_common.h"
35 #include "notification_service.h"
36 #include "badge_service.h"
37 #include "shortcut_service.h"
38
39 #define DBUS_NAME "org.freedesktop.DBus"
40 #define DBUS_OBJECT_PATH "/org/freedesktop/DBus"
41 #define DBUS_INTERFACE_NAME "org.freedesktop.DBus"
42
43 #define PROVIDER_BUS_NAME "org.tizen.data_provider_service"
44 #define PROVIDER_OBJECT_PATH "/org/tizen/data_provider_service"
45
46 static GDBusConnection *_gdbus_conn;
47 static GHashTable *_noti_pkg_privilege_info;
48 static GHashTable *_badge_pkg_privilege_info;
49
50 uid_t get_sender_uid(const char *sender_name)
51 {
52         GDBusMessage *msg = NULL;
53         GDBusMessage *reply = NULL;
54         GError *err = NULL;
55         GVariant *body;
56         uid_t uid = 0;
57
58         msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
59                         DBUS_INTERFACE_NAME, "GetConnectionUnixUser");
60         if (!msg) {
61                 LOGE("Failed to alloc new method call");
62                 goto out;
63         }
64
65         g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
66         reply = g_dbus_connection_send_message_with_reply_sync(_gdbus_conn, msg,
67                         G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err);
68
69         if (!reply) {
70                 if (err != NULL) {
71                         LOGE("Failed to get uid [%s]", err->message);
72                         g_error_free(err);
73                 }
74                 goto out;
75         }
76
77         body = g_dbus_message_get_body(reply);
78         g_variant_get(body, "(u)", &uid);
79
80 out:
81         if (msg)
82                 g_object_unref(msg);
83         if (reply)
84                 g_object_unref(reply);
85
86         return uid;
87 }
88
89 pid_t get_sender_pid(const char *sender_name)
90 {
91         GDBusMessage *msg = NULL;
92         GDBusMessage *reply = NULL;
93         GError *err = NULL;
94         GVariant *body;
95         pid_t pid = 0;
96
97         msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
98                         DBUS_INTERFACE_NAME, "GetConnectionUnixProcessID");
99         if (!msg) {
100                 LOGE("Failed to alloc new method call");
101                 goto out;
102         }
103
104         g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
105         reply = g_dbus_connection_send_message_with_reply_sync(_gdbus_conn, msg,
106                         G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err);
107
108         if (!reply) {
109                 if (err != NULL) {
110                         LOGE("Failed to get uid [%s]", err->message);
111                         g_error_free(err);
112                 }
113                 goto out;
114         }
115
116         body = g_dbus_message_get_body(reply);
117         g_variant_get(body, "(u)", &pid);
118
119 out:
120         if (msg)
121                 g_object_unref(msg);
122         if (reply)
123                 g_object_unref(reply);
124
125         return pid;
126 }
127
128 bool is_existed_busname(const char *sender_name)
129 {
130         GDBusMessage *msg = NULL;
131         GDBusMessage *reply = NULL;
132         GError *err = NULL;
133         GVariant *body;
134         bool is_existed = false;
135
136         msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
137                         DBUS_INTERFACE_NAME, "NameHasOwner");
138         if (!msg) {
139                 LOGE("Failed to alloc new method call");
140                 goto out;
141         }
142
143         g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
144         reply = g_dbus_connection_send_message_with_reply_sync(_gdbus_conn, msg,
145                         G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err);
146
147         if (!reply) {
148                 if (err != NULL) {
149                         LOGE("Failed to get uid [%s]", err->message);
150                         g_error_free(err);
151                 }
152                 goto out;
153         }
154
155         body = g_dbus_message_get_body(reply);
156         g_variant_get(body, "(b)", &is_existed);
157
158 out:
159         if (msg)
160                 g_object_unref(msg);
161         if (reply)
162                 g_object_unref(reply);
163
164         return is_existed;
165 }
166
167 int send_notify(GVariant *body, char *cmd, GHashTable **monitoring_hash, char *interface_name, uid_t uid)
168 {
169         GError *err = NULL;
170         GList *monitoring_list = NULL;
171         GList *target_list;
172         char *target_bus_name;
173         int monitoring_count = 0;
174         bool is_existed = false;
175
176         monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(uid));
177         target_list = g_list_first(monitoring_list);
178         for (; target_list != NULL; ) {
179                 err = NULL;
180                 target_bus_name = target_list->data;
181                 target_list = target_list->next;
182
183                 if (g_variant_is_floating(body))
184                         g_variant_ref(body);
185
186                 if (g_dbus_connection_emit_signal(_gdbus_conn,
187                                         target_bus_name,
188                                         PROVIDER_OBJECT_PATH,
189                                         interface_name,
190                                         cmd,
191                                         body,
192                                         &err) == FALSE) {
193                         if (err != NULL) {
194                                 ERR("Emit signal err [%s]", err->message);
195                                 g_error_free(err);
196                         }
197                         is_existed = is_existed_busname(target_bus_name);
198                         if (is_existed == false)
199                                 delete_monitoring_list(monitoring_hash, target_bus_name, uid);
200                         ERR("Fail, emit signal to [%s]", target_bus_name);
201                 }
202                 monitoring_count++;
203                 DBG("Success, emit signal to [%s]", target_bus_name);
204         }
205
206         DBG("Success, cmd[%s] monitoring count[%d]", cmd, monitoring_count);
207         return SERVICE_COMMON_ERROR_NONE;
208 }
209
210 int send_event_notify_by_busname(GVariant *body, char *cmd, char *busname, char *interface_name)
211 {
212         GError *err = NULL;
213
214         if (g_variant_is_floating(body))
215                 g_variant_ref(body);
216
217         if (g_dbus_connection_emit_signal(_gdbus_conn,
218                                           busname,
219                                           PROVIDER_OBJECT_PATH,
220                                           interface_name,
221                                           cmd,
222                                           body,
223                                           &err) == FALSE) {
224                 if (err != NULL) {
225                         ERR("Emit signal err [%s]",
226                                         err->message);
227                         g_error_free(err);
228                 }
229                 ERR("Failed to emit signal to [%s]", busname);
230                 return SERVICE_COMMON_ERROR_IO_ERROR;
231         }
232         DBG("Success, Emit signal to [%s] cmd[%s]", busname, cmd);
233         return SERVICE_COMMON_ERROR_NONE;
234 }
235
236 /* register service */
237
238 static int _monitoring_app_list_compare_cb(gconstpointer a, gconstpointer b)
239 {
240         return strcmp(a, b);
241 }
242
243 int service_register(GVariant *parameters, GVariant **reply_body, const gchar *sender,
244                 GBusNameAppearedCallback name_appeared_handler,
245                 GBusNameVanishedCallback name_vanished_handler,
246                 GHashTable **monitoring_hash,
247                 uid_t uid)
248 {
249         GList *added_list = NULL;
250         const char *bus_name = sender;
251         monitoring_info_s *m_info = NULL;
252         uid_t request_uid = 0;
253         GList *monitoring_list = NULL;
254
255         if (sender == NULL)
256                 return SERVICE_COMMON_ERROR_IO_ERROR;
257
258         g_variant_get(parameters, "(i)", &request_uid);
259         if (uid > NORMAL_UID_BASE && uid != request_uid)
260                 return SERVICE_COMMON_ERROR_IO_ERROR;
261
262         DBG("service_register : uid %d , request_uid %d", uid, request_uid);
263         monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(request_uid));
264         added_list = g_list_find_custom(monitoring_list, bus_name,
265                         (GCompareFunc)_monitoring_app_list_compare_cb);
266
267         if (added_list == NULL) {
268                 DBG("add new sender to list");
269                 m_info = (monitoring_info_s *)calloc(1, sizeof(monitoring_info_s));
270                 if (m_info == NULL) {
271                         ERR("Failed to alloc memory");
272                         return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
273                 }
274
275                 m_info->bus_name = strdup(bus_name);
276                 m_info->uid = request_uid;
277                 m_info->watcher_id = g_bus_watch_name_on_connection(
278                                 _gdbus_conn,
279                                 bus_name,
280                                 G_BUS_NAME_WATCHER_FLAGS_NONE,
281                                 name_appeared_handler,
282                                 name_vanished_handler,
283                                 m_info,
284                                 NULL);
285                 if (m_info->watcher_id == 0) {
286                         ERR("Fail to watch name [%s]", bus_name);
287                         free(m_info->bus_name);
288                         free(m_info);
289                         return SERVICE_COMMON_ERROR_IO_ERROR;
290                 }
291                 DBG("Watch on [%s] success", bus_name);
292
293                 monitoring_list = g_list_append(monitoring_list, strdup(bus_name));
294                 DBG("Success, sender[%s] length[%d]",
295                                 sender, g_list_length(monitoring_list));
296                 if (g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(request_uid)) == NULL)
297                         g_hash_table_insert(*monitoring_hash, GUINT_TO_POINTER(request_uid), monitoring_list);
298         } else {
299                 ERR("Sender [%s] already exist", sender);
300         }
301
302         *reply_body = g_variant_new("()");
303         if (*reply_body == NULL) {
304                 if (m_info) {
305                         if (m_info->bus_name)
306                                 free(m_info->bus_name);
307                         free(m_info);
308                 }
309                 monitoring_list = g_list_remove(monitoring_list, bus_name);
310                 ERR("Failed to make reply");
311                 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
312         }
313         return SERVICE_COMMON_ERROR_NONE;
314 }
315
316 int delete_monitoring_list(GHashTable **monitoring_hash, const char *sender, uid_t uid)
317 {
318         GList *monitoring_list = NULL;
319         GList *del_list = NULL;
320         char *bus_name;
321
322         monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(uid));
323         if (monitoring_list == NULL) {
324                 ERR("No uid[%d] in monitoring hash", uid);
325                 return SERVICE_COMMON_ERROR_IO_ERROR;
326         }
327
328         monitoring_list = g_list_first(monitoring_list);
329         del_list = g_list_find_custom(monitoring_list, sender,
330                         (GCompareFunc)_monitoring_app_list_compare_cb);
331
332         if (del_list) {
333                 DBG("Find delete list - uid[%d] sender[%s]", uid, sender);
334                 bus_name = g_list_nth_data(del_list, 0);
335                 if (bus_name)
336                         free(bus_name);
337                 monitoring_list = g_list_delete_link(monitoring_list, del_list);
338
339                 if (monitoring_list == NULL) {
340                         g_hash_table_steal(*monitoring_hash, GUINT_TO_POINTER(uid));
341                 } else {
342                         monitoring_list = g_list_first(monitoring_list);
343                         g_hash_table_replace(*monitoring_hash, GUINT_TO_POINTER(uid), monitoring_list);
344                 }
345         }
346         return SERVICE_COMMON_ERROR_NONE;
347 }
348
349 static int _dbus_init(void)
350 {
351         GError *error = NULL;
352
353         if (_gdbus_conn == NULL) {
354                 _gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
355                 if (_gdbus_conn == NULL) {
356                         if (error != NULL) {
357                                 ERR("Failed to get dbus [%s]", error->message);
358                                 g_error_free(error);
359                         }
360                         return SERVICE_COMMON_ERROR_IO_ERROR;
361                 }
362         }
363
364         return SERVICE_COMMON_ERROR_NONE;
365 }
366
367 int service_common_register_dbus_interface(char *introspection_xml, GDBusInterfaceVTable interface_vtable)
368 {
369         int result;
370         int owner_id, noti_registration_id;
371         GError *error = NULL;
372         GDBusNodeInfo *introspection_data = NULL;
373
374         result = _dbus_init();
375         if (result != SERVICE_COMMON_ERROR_NONE) {
376                         ERR("Can't init dbus [%d]", result);
377                         result = SERVICE_COMMON_ERROR_IO_ERROR;
378                         goto out;
379         }
380
381         owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
382                         PROVIDER_BUS_NAME,
383                         G_BUS_NAME_OWNER_FLAGS_NONE,
384                         NULL,
385                         NULL,
386                         NULL,
387                         NULL, NULL);
388         if (!owner_id) {
389                 ERR("Failed to own name");
390                 result = SERVICE_COMMON_ERROR_IO_ERROR;
391                 goto out;
392         }
393
394         DBG("Acquiring the own name [%d]", owner_id);
395         introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, &error);
396         if (!introspection_data) {
397                 ERR("g_dbus_node_info_new_for_xml is failed.");
398                 result = SERVICE_COMMON_ERROR_IO_ERROR;
399                 if (error != NULL) {
400                         ERR("g_dbus_node_info_new_for_xml err [%s]", error->message);
401                         g_error_free(error);
402                 }
403                 goto out;
404         }
405
406         noti_registration_id = g_dbus_connection_register_object(_gdbus_conn,
407                         PROVIDER_OBJECT_PATH, introspection_data->interfaces[0],
408                         &interface_vtable, NULL, NULL, NULL);
409
410         DBG("registration id[%d]", noti_registration_id);
411         if (noti_registration_id == 0) {
412                 ERR("Failed to g_dbus_connection_register_object");
413                 result = SERVICE_COMMON_ERROR_IO_ERROR;
414                 goto out;
415         }
416
417 out:
418         if (introspection_data)
419                 g_dbus_node_info_unref(introspection_data);
420
421         return result;
422 }
423
424 static int _init_pkg_privilege_info() {
425
426         if (_noti_pkg_privilege_info != NULL)
427                 return 0;
428
429         _noti_pkg_privilege_info =
430                 g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
431         _badge_pkg_privilege_info =
432                 g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
433         DBG("init pkg privilege info done");
434         return 0;
435 }
436
437 static int _package_install_cb(uid_t uid, const char *pkgname, enum pkgmgr_status status, double value, void *data)
438 {
439         int ret;
440         gpointer tmp;
441         int privilege_info;
442
443         if (status != PKGMGR_STATUS_END)
444                 return 0;
445
446         if (uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))
447                 uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
448
449         _init_pkg_privilege_info();
450         if (g_hash_table_contains(_noti_pkg_privilege_info, pkgname)) {
451                 tmp = g_hash_table_lookup(_noti_pkg_privilege_info, pkgname);
452                 privilege_info = GPOINTER_TO_UINT(tmp);
453                 if (privilege_info == 1)
454                         notification_setting_db_update_pkg_disabled(pkgname, false, uid);
455
456                 g_hash_table_remove(_noti_pkg_privilege_info, pkgname);
457         } else {
458                 /* In consideration of the reboot status, change the disable information. */
459                 ret = notification_setting_db_update_pkg_disabled(pkgname, false, uid);
460                 if (ret != NOTIFICATION_ERROR_NONE)
461                         notification_setting_insert_package_for_uid(pkgname, uid);
462         }
463
464         if (g_hash_table_contains(_badge_pkg_privilege_info, pkgname)) {
465                 tmp = g_hash_table_lookup(_badge_pkg_privilege_info, pkgname);
466                 privilege_info = GPOINTER_TO_UINT(tmp);
467                 if (privilege_info == 1)
468                         badge_db_update_pkg_disabled(pkgname, false, uid);
469
470                 g_hash_table_remove(_badge_pkg_privilege_info, pkgname);
471         } else {
472                 /* In consideration of the reboot status, change the disable information. */
473                 ret = badge_db_update_pkg_disabled(pkgname, false, uid);
474                 if (ret != BADGE_ERROR_NONE)
475                         badge_setting_insert_package_for_uid(pkgname, uid);
476         }
477
478         return 0;
479 }
480
481 static int _package_uninstall_cb(uid_t uid, const char *pkgname, enum pkgmgr_status status, double value, void *data)
482 {
483         int ret;
484         pkgmgrinfo_pkginfo_h pkginfo;
485
486         if (status != PKGMGR_STATUS_END)
487                 return 0;
488
489         if (uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))
490                 uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
491
492         ret = pkgmgrinfo_pkginfo_get_usr_disabled_pkginfo(pkgname, uid, &pkginfo);
493         if (ret == PMINFO_R_OK) {
494                 pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
495
496                 _init_pkg_privilege_info();
497                 ret = notification_setting_db_update_pkg_disabled(pkgname, true, uid);
498                 if (ret == NOTIFICATION_ERROR_NONE)
499                         g_hash_table_insert(_noti_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(1));
500                 else
501                         g_hash_table_insert(_noti_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(0));
502
503                 ret = badge_db_update_pkg_disabled(pkgname, true, uid);
504                 if (ret == BADGE_ERROR_NONE)
505                         g_hash_table_insert(_badge_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(1));
506                 else
507                         g_hash_table_insert(_badge_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(0));
508         } else {
509                 notification_setting_delete_package_for_uid(pkgname, uid);
510                 badge_db_delete_by_pkgname(pkgname, uid);
511                 badge_setting_delete_package_for_uid(pkgname, uid);
512                 notification_noti_delete_template(pkgname);
513         }
514
515         return 0;
516 }
517
518 static int _app_enabled_cb(uid_t uid, const char *app_id, enum pkgmgr_status status, double value, void *data)
519 {
520         if (status == PKGMGR_STATUS_END)
521                 notification_setting_db_update_app_disabled(app_id, false, uid);
522
523         return 0;
524 }
525
526 static int _app_disabled_cb(uid_t uid, const char *app_id, enum pkgmgr_status status, double value, void *data)
527 {
528         if (status == PKGMGR_STATUS_END) {
529                 notification_delete_noti_by_app_id(app_id, uid);
530                 notification_setting_db_update_app_disabled(app_id, true, uid);
531         }
532
533         return 0;
534 }
535
536 void service_common_init(void)
537 {
538         pkgmgr_init();
539         pkgmgr_add_event_callback(PKGMGR_EVENT_INSTALL, _package_install_cb, NULL);
540         pkgmgr_add_event_callback(PKGMGR_EVENT_UPDATE, _package_install_cb, NULL);
541         pkgmgr_add_event_callback(PKGMGR_EVENT_UNINSTALL, _package_uninstall_cb, NULL);
542         pkgmgr_add_event_callback(PKGMGR_EVENT_APP_ENABLE, _app_enabled_cb, NULL);
543         pkgmgr_add_event_callback(PKGMGR_EVENT_APP_DISABLE, _app_disabled_cb, NULL);
544 }
545
546 void service_common_set_connection(GDBusConnection *conn)
547 {
548         _gdbus_conn = conn;
549 }