2 * Copyright (c) 2011 - 2017 Samsung Electronics Co., Ltd. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
30 #include "shortcut_private.h"
31 #include "shortcut_internal.h"
33 #define SHORTCUT_PKGNAME_LEN 512
34 #define REQUEST_ID_LEN 40
37 #define PROVIDER_BUS_NAME "org.tizen.data_provider_service"
38 #define PROVIDER_OBJECT_PATH "/org/tizen/data_provider_service"
39 #define PROVIDER_SHORTCUT_INTERFACE_NAME "org.tizen.data_provider_shortcut_service"
41 #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
42 #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
43 #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
45 static GDBusConnection *_gdbus_conn = NULL;
46 static int monitor_id = 0;
47 static int provider_monitor_id = 0;
49 typedef struct _shortcut_request_cb_info {
50 int (*request_cb)(const char *appid, const char *name, int type, const char *content, const char *icon, pid_t pid, double period, int allow_duplicate, void *data);
52 } shortcut_request_cb_info;
54 typedef struct _shortcut_remove_cb_info {
55 int (*remove_cb)(const char *package_name, const char *name, int sender_pid, void *user_data);
57 } shortcut_remove_cb_info;
59 static shortcut_request_cb_info _request_callback_info;
60 static shortcut_remove_cb_info _remove_callback_info;
62 static void _shortcut_send_return(int ret_val, const char *request_id)
65 GDBusMessage *reply = NULL;
68 if (ret != SHORTCUT_ERROR_NONE) {
69 SHORTCUT_ERR("Can't init dbus %d", ret);
73 _send_sync_shortcut(g_variant_new("(is)", ret_val, request_id),
74 &reply, "send_return_value");
76 g_object_unref(reply);
80 static void _add_shortcut_notify(GVariant *parameters)
82 int ret = SHORTCUT_ERROR_NONE;
90 const char *request_id;
92 g_variant_get(parameters, "(&si&s&si&s&si)", &request_id, &sender_pid, &appid, &name, &type, &content, &icon, &allow_duplicate);
93 SHORTCUT_DBG("_add_shortcut_notify sender pid : [%d] appid : [%s]", sender_pid, appid);
95 if (_request_callback_info.request_cb != NULL)
96 ret = _request_callback_info.request_cb(appid, name, type, content, icon, sender_pid, -1.0f, allow_duplicate, _request_callback_info.data);
98 SHORTCUT_DBG("request_cb is null.");
100 _shortcut_send_return(ret, request_id);
104 /* LCOV_EXCL_START */
105 static void _add_shortcut_widget_notify(GVariant *parameters)
107 int ret = SHORTCUT_ERROR_NONE;
116 const char *request_id;
118 g_variant_get(parameters, "(&si&s&si&s&sdi)", &request_id, &sender_pid, &appid, &name, &type, &content, &icon, &period, &allow_duplicate);
119 SHORTCUT_DBG("_add_shortcut_widget_notify sender pid : [%d] appid : [%s]", sender_pid, appid);
121 if (_request_callback_info.request_cb != NULL)
122 ret = _request_callback_info.request_cb(appid, name, type, content, icon, sender_pid, period, allow_duplicate, _request_callback_info.data);
124 SHORTCUT_DBG("request_cb is null.");
126 _shortcut_send_return(ret, request_id);
130 static void _remove_shortcut_notify(GVariant *parameters)
132 int ret = SHORTCUT_ERROR_NONE;
136 const char *request_id;
138 g_variant_get(parameters, "(&si&s&s)", &request_id, &sender_pid, &appid, &name);
139 SHORTCUT_DBG("_remove_shortcut_notify sender pid : [%d] appid : [%s]", sender_pid, appid);
141 if (_remove_callback_info.remove_cb != NULL)
142 ret = _remove_callback_info.remove_cb(appid, name, sender_pid, _remove_callback_info.data);
144 SHORTCUT_DBG("remove_cb is null.");
146 _shortcut_send_return(ret, request_id);
149 /* LCOV_EXCL_START */
150 static void _handle_shortcut_notify(GDBusConnection *connection,
151 const gchar *sender_name,
152 const gchar *object_path,
153 const gchar *interface_name,
154 const gchar *signal_name,
155 GVariant *parameters,
158 SHORTCUT_DBG("signal_name : [%s]", signal_name);
159 if (g_strcmp0(signal_name, "add_shortcut_notify") == 0)
160 _add_shortcut_notify(parameters);
161 else if (g_strcmp0(signal_name, "add_shortcut_widget_notify") == 0)
162 _add_shortcut_widget_notify(parameters);
163 else if (g_strcmp0(signal_name, "remove_shortcut_notify") == 0)
164 _remove_shortcut_notify(parameters);
170 GError *error = NULL;
172 if (_gdbus_conn == NULL) {
173 _gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
175 if (_gdbus_conn == NULL) {
176 /* LCOV_EXCL_START */
179 SHORTCUT_ERR("Failed to get dbus [%s]", error->message);
183 return SHORTCUT_ERROR_IO_ERROR;
186 shortcut_error_quark();
189 return SHORTCUT_ERROR_NONE;
192 int _dbus_signal_init(void)
194 int ret = SHORTCUT_ERROR_NONE;
197 if (monitor_id == 0) {
198 id = g_dbus_connection_signal_subscribe(
201 PROVIDER_SHORTCUT_INTERFACE_NAME, /* interface */
203 PROVIDER_OBJECT_PATH, /* path */
205 G_DBUS_SIGNAL_FLAGS_NONE,
206 _handle_shortcut_notify,
209 SHORTCUT_DBG("subscribe id : %d", id);
211 /* LCOV_EXCL_START */
212 ret = SHORTCUT_ERROR_IO_ERROR;
213 SHORTCUT_ERR("Failed to _register_noti_dbus_interface");
216 SHORTCUT_INFO("get dbus connection success");
224 char *_shortcut_get_pkgname_by_pid(void)
226 char pkgname[SHORTCUT_PKGNAME_LEN + 1] = { 0, };
227 char buf[SHORTCUT_PKGNAME_LEN + 1] = { 0, };
234 ret = aul_app_get_pkgname_bypid(pid, pkgname, sizeof(pkgname));
236 /* LCOV_EXCL_START */
237 snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
239 fd = open(buf, O_RDONLY);
243 ret = read(fd, pkgname, sizeof(pkgname) - 1);
253 * "ret" is not able to be larger than "sizeof(pkgname) - 1",
254 * if the system is not going wrong.
257 if (strlen(pkgname) <= 0)
261 dup_pkgname = strdup(pkgname);
263 SHORTCUT_ERR("Heap: %d\n", errno); /* LCOV_EXCL_LINE */
269 * implement user request
271 int _send_sync_shortcut(GVariant *body, GDBusMessage **reply, char *cmd)
275 int ret = SHORTCUT_ERROR_NONE;
277 msg = g_dbus_message_new_method_call(
279 PROVIDER_OBJECT_PATH,
280 PROVIDER_SHORTCUT_INTERFACE_NAME,
283 /* LCOV_EXCL_START */
284 SHORTCUT_ERR("Can't allocate new method call");
286 g_variant_unref(body);
287 return SHORTCUT_ERROR_OUT_OF_MEMORY;
292 g_dbus_message_set_body(msg, body);
294 *reply = g_dbus_connection_send_message_with_reply_sync(
297 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
306 /* LCOV_EXCL_START */
307 ret = SHORTCUT_ERROR_COMM;
309 SHORTCUT_ERR("No reply. cmd = %s, error = %s", cmd, err->message);
310 if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
311 ret = SHORTCUT_ERROR_PERMISSION_DENIED;
318 if (g_dbus_message_to_gerror(*reply, &err)) {
319 /* LCOV_EXCL_START */
320 if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
321 ret = SHORTCUT_ERROR_PERMISSION_DENIED;
325 SHORTCUT_ERR("_send_sync_shortcut error %s err code: %d", err->message, ret);
331 SHORTCUT_DBG("_send_sync_shortcut done !!");
332 return SHORTCUT_ERROR_NONE;
335 int _send_service_register(void)
337 GDBusMessage *reply = NULL;
340 result = _send_sync_shortcut(g_variant_new("(i)", getuid()), &reply, "shortcut_service_register");
342 g_object_unref(reply);
343 SHORTCUT_DBG("_send_service_register done");
347 static void _send_message_with_reply_sync_cb(GDBusConnection *connection,
353 GDBusMessage *reply = NULL;
355 struct result_cb_item *cb_item = (struct result_cb_item *)user_data;
357 if (cb_item == NULL) {
358 /* LCOV_EXCL_START */
359 SHORTCUT_ERR("Failed to get a callback item");
364 reply = g_dbus_connection_send_message_with_reply_finish(
370 /* LCOV_EXCL_START */
372 SHORTCUT_ERR("No reply. error = %s", err->message);
375 result = SHORTCUT_ERROR_COMM;
379 if (g_dbus_message_to_gerror(reply, &err)) {
380 /* LCOV_EXCL_START */
381 if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
382 result = SHORTCUT_ERROR_PERMISSION_DENIED;
386 SHORTCUT_ERR("_send_message_with_reply_sync_cb error %s err code: %d", err->message, result);
390 body = g_dbus_message_get_body(reply);
391 g_variant_get(body, "(i)", &result);
394 if (cb_item->result_internal_cb)
395 cb_item->result_internal_cb(result, getpid(), cb_item->data); /* LCOV_EXCL_LINE */
396 else if (cb_item->result_cb)
397 cb_item->result_cb(result, cb_item->data);
400 g_object_unref(reply);
405 int _send_async_shortcut(GVariant *body, struct result_cb_item *cb_item, char *cmd)
409 msg = g_dbus_message_new_method_call(
411 PROVIDER_OBJECT_PATH,
412 PROVIDER_SHORTCUT_INTERFACE_NAME,
415 /* LCOV_EXCL_START */
416 SHORTCUT_ERR("Can't allocate new method call");
417 return SHORTCUT_ERROR_OUT_OF_MEMORY;
421 if (g_variant_is_floating(body))
425 g_dbus_message_set_body(msg, body);
427 g_dbus_connection_send_message_with_reply(
430 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
434 (GAsyncReadyCallback)_send_message_with_reply_sync_cb,
440 SHORTCUT_DBG("_send_async_shortcut done !!");
441 return SHORTCUT_ERROR_NONE;
444 int _check_privilege(void)
446 GDBusMessage *reply = NULL;
447 int ret = SHORTCUT_ERROR_NONE;
449 ret = _send_sync_shortcut(NULL, &reply, "check_privilege");
452 g_object_unref(reply);
458 /* LCOV_EXCL_START */
459 static void _on_name_appeared(GDBusConnection *connection,
461 const gchar *name_owner,
464 SHORTCUT_DBG("name appeared : %s", name);
465 _send_service_register();
469 /* LCOV_EXCL_START */
470 static void _on_name_vanished(GDBusConnection *connection,
474 SHORTCUT_DBG("name vanished : %s", name);
478 void _ipc_monitor_fini(void)
480 if (provider_monitor_id) {
481 g_bus_unwatch_name(provider_monitor_id);
482 provider_monitor_id = 0;
486 g_dbus_connection_signal_unsubscribe(_gdbus_conn, monitor_id);
491 g_object_unref(_gdbus_conn);
497 void _set_request_cb(shortcut_request_cb request_cb, void *data)
499 _request_callback_info.request_cb = request_cb;
500 _request_callback_info.data = data;
503 void _unset_request_cb(void)
505 if (_remove_callback_info.remove_cb == NULL &&
506 _remove_callback_info.data == NULL)
509 _request_callback_info.request_cb = NULL;
510 _request_callback_info.data = NULL;
513 void _set_remove_cb(shortcut_remove_cb remove_cb, void *data)
515 _remove_callback_info.remove_cb = remove_cb;
516 _remove_callback_info.data = data;
519 void _unset_remove_cb(void)
521 if (_request_callback_info.request_cb == NULL &&
522 _request_callback_info.data == NULL)
525 _remove_callback_info.remove_cb = NULL;
526 _remove_callback_info.data = NULL;
529 int _dbus_set_watch_name(void)
531 if (provider_monitor_id == 0) {
532 provider_monitor_id = g_bus_watch_name_on_connection(
535 G_BUS_NAME_WATCHER_FLAGS_NONE,
541 if (provider_monitor_id == 0) {
542 /* LCOV_EXCL_START */
543 SHORTCUT_ERR("watch on name fail");
544 return SHORTCUT_ERROR_IO_ERROR;
549 return SHORTCUT_ERROR_NONE;
552 char *_make_request_id(void)
555 char request_id[REQUEST_ID_LEN];
557 g_atomic_int_inc(&id);
558 snprintf(request_id, sizeof(request_id), "%d@%d", getpid(), id);
560 SHORTCUT_DBG("The request_id of shortcut is [%s]", request_id);
562 return strdup(request_id);
565 int _ready_to_send(char **appid, char **request_id)
570 if (ret != SHORTCUT_ERROR_NONE) {
571 /* LCOV_EXCL_START */
572 SHORTCUT_ERR("Can't init dbus %d", ret);
577 ret = _check_privilege();
578 if (ret != SHORTCUT_ERROR_NONE)
581 *appid = _shortcut_get_pkgname_by_pid();
582 if (*appid == NULL) {
583 /* LCOV_EXCL_START */
584 SHORTCUT_ERR("Can't get appid");
585 return SHORTCUT_ERROR_IO_ERROR;
589 *request_id = _make_request_id();
590 if (*request_id == NULL) {
591 SHORTCUT_ERR("Can't get request_id");
594 return SHORTCUT_ERROR_OUT_OF_MEMORY;
597 return SHORTCUT_ERROR_NONE;
600 EAPI int shortcut_add_to_home_sync(const char *name, shortcut_type type,
601 const char *uri, const char *icon, int allow_duplicate)
605 char *request_id = NULL;
607 GVariant *reply_body;
608 GDBusMessage *reply = NULL;
610 CHECK_SHORTCUT_FEATURE();
612 if (ADD_TO_HOME_IS_DYNAMICBOX(type)) {
613 /* LCOV_EXCL_START */
614 SHORTCUT_ERR("Invalid type used for adding a shortcut\n");
615 return SHORTCUT_ERROR_INVALID_PARAMETER;
619 ret = _ready_to_send(&appid, &request_id);
620 if (ret != SHORTCUT_ERROR_NONE) {
621 /* LCOV_EXCL_START */
622 SHORTCUT_ERR("ready to send error [%d]", ret);
636 body = g_variant_new("(sississi)", request_id, getpid(), appid, name,
637 type, uri, icon, allow_duplicate);
639 ret = _send_sync_shortcut(body, &reply, "add_shortcut");
640 if (ret == SHORTCUT_ERROR_NONE) {
641 reply_body = g_dbus_message_get_body(reply);
642 g_variant_get(reply_body, "(i)", &ret);
648 g_variant_unref(body);
652 g_object_unref(reply);
654 SHORTCUT_DBG("result[%d]", ret);
659 EAPI int shortcut_add_to_home_widget_sync(const char *name,
660 shortcut_widget_size_e size, const char *widget_id,
661 const char *icon, double period, int allow_duplicate)
665 char *request_id = NULL;
667 GVariant *reply_body;
668 GDBusMessage *reply = NULL;
670 CHECK_SHORTCUT_FEATURE();
673 SHORTCUT_ERR("AppID is null\n");
674 return SHORTCUT_ERROR_INVALID_PARAMETER;
677 if (!SHORTCUT_IS_WIDGET_SIZE(size)) {
678 /* LCOV_EXCL_START */
679 SHORTCUT_ERR("Invalid type used for adding a widget\n");
680 return SHORTCUT_ERROR_INVALID_PARAMETER;
684 ret = _ready_to_send(&appid, &request_id);
685 if (ret != SHORTCUT_ERROR_NONE) {
686 /* LCOV_EXCL_START */
687 SHORTCUT_ERR("ready to send error [%d]", ret);
692 body = g_variant_new("(sississdi)", request_id, getpid(), widget_id,
693 name, size, NULL, icon, period, allow_duplicate);
695 ret = _send_sync_shortcut(body, &reply, "add_shortcut_widget");
696 if (ret == SHORTCUT_ERROR_NONE) {
697 reply_body = g_dbus_message_get_body(reply);
698 g_variant_get(reply_body, "(i)", &ret);
704 g_variant_unref(body);
708 g_object_unref(reply);
710 SHORTCUT_DBG("result[%d]", ret);
715 EAPI int shortcut_remove_from_home_sync(const char *name)
719 char *request_id = NULL;
721 GVariant *reply_body;
722 GDBusMessage *reply = NULL;
724 CHECK_SHORTCUT_FEATURE();
727 SHORTCUT_ERR("name is NULL.");
728 return SHORTCUT_ERROR_INVALID_PARAMETER;
731 ret = _ready_to_send(&appid, &request_id);
732 if (ret != SHORTCUT_ERROR_NONE) {
733 /* LCOV_EXCL_START */
734 SHORTCUT_ERR("ready to send error [%d]", ret);
739 body = g_variant_new("(siss)", request_id, getpid(), appid, name);
741 ret = _send_sync_shortcut(body, &reply, "remove_shortcut");
742 if (ret == SHORTCUT_ERROR_NONE) {
743 reply_body = g_dbus_message_get_body(reply);
744 g_variant_get(reply_body, "(i)", &ret);
750 g_variant_unref(body);
754 g_object_unref(reply);
756 SHORTCUT_DBG("result[%d]", ret);