2 * Copyright (c) 2016 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.
20 #include <sys/types.h>
26 #include "package-manager.h"
27 #include "package-manager-types.h"
28 #include "pkgmgr_client_debug.h"
29 #include "pkgmgr_client_internal.h"
30 #include "../../installer/pkgmgr_installer.h"
31 #include "../../installer/pkgmgr_installer_config.h"
33 #define CONNECTION_RETRY_MAX 5
34 #define CONNECTION_WAIT_USEC (1000000 / 2) /* 0.5 sec */
35 #define CONNECTION_TIMEOUT_MSEC 5000 /* 5 sec */
36 #define REGULAR_USER 5000
38 static int _is_system_user(void)
42 if (uid < REGULAR_USER)
48 static GBusType __get_bus_type(pkgmgr_client_type type)
50 if (type == PC_REQUEST || _is_system_user())
51 return G_BUS_TYPE_SYSTEM;
53 return G_BUS_TYPE_SESSION;
56 int pkgmgr_client_connection_connect(struct pkgmgr_client_t *pc)
61 #if !GLIB_CHECK_VERSION(2, 35, 0)
64 bus_type = __get_bus_type(pc->pc_type);
65 pc->conn = g_bus_get_sync(bus_type, NULL, &error);
67 ERR("gdbus connection error (%s)", error->message);
69 return PKGMGR_R_ECOMM;
75 void pkgmgr_client_connection_disconnect(struct pkgmgr_client_t *pc)
77 /* flush remaining buffer: blocking mode */
78 g_dbus_connection_flush_sync(pc->conn, NULL, NULL);
79 g_object_unref(pc->conn);
84 const char *signal_str;
88 struct signal_map map[] = {
89 {PKGMGR_INSTALLER_INSTALL_EVENT_STR, PKGMGR_CLIENT_STATUS_INSTALL},
90 {PKGMGR_INSTALLER_UNINSTALL_EVENT_STR, PKGMGR_CLIENT_STATUS_UNINSTALL},
91 {PKGMGR_INSTALLER_UPGRADE_EVENT_STR, PKGMGR_CLIENT_STATUS_UPGRADE},
92 {PKGMGR_INSTALLER_CLEAR_EVENT_STR, PKGMGR_CLIENT_STATUS_CLEAR_DATA},
93 {PKGMGR_INSTALLER_MOVE_EVENT_STR, PKGMGR_CLIENT_STATUS_MOVE},
94 {PKGMGR_INSTALLER_INSTALL_PERCENT_KEY_STR,
95 PKGMGR_CLIENT_STATUS_INSTALL_PROGRESS},
96 {PKGMGR_INSTALLER_GET_SIZE_KEY_STR, PKGMGR_CLIENT_STATUS_GET_SIZE},
97 {PKGMGR_INSTALLER_CLEAR_CACHE_KEY_STR,
98 PKGMGR_CLIENT_STATUS_CLEAR_CACHE},
99 {PKGMGR_INSTALLER_APP_ENABLE_EVENT_STR,
100 PKGMGR_CLIENT_STATUS_ENABLE_APP},
101 {PKGMGR_INSTALLER_APP_DISABLE_EVENT_STR,
102 PKGMGR_CLIENT_STATUS_DISABLE_APP},
103 {PKGMGR_INSTALLER_APP_ENABLE_SPLASH_SCREEN_EVENT_STR,
104 PKGMGR_CLIENT_STATUS_ENABLE_APP_SPLASH_SCREEN},
105 {PKGMGR_INSTALLER_APP_DISABLE_SPLASH_SCREEN_EVENT_STR,
106 PKGMGR_CLIENT_STATUS_DISABLE_APP_SPLASH_SCREEN},
107 {PKGMGR_INSTALLER_RES_COPY_EVENT_STR, PKGMGR_CLIENT_STATUS_RES_COPY},
108 {PKGMGR_INSTALLER_RES_CREATE_DIR_EVENT_STR,
109 PKGMGR_CLIENT_STATUS_RES_CREATE_DIR},
110 {PKGMGR_INSTALLER_RES_REMOVE_EVENT_STR,
111 PKGMGR_CLIENT_STATUS_RES_REMOVE},
112 {PKGMGR_INSTALLER_RES_UNINSTALL_EVENT_STR,
113 PKGMGR_CLIENT_STATUS_RES_UNINSTALL},
117 static int __get_signal_type(const char *name)
124 for (i = 0; map[i].signal_str != NULL; i++) {
125 if (strcmp(map[i].signal_str, name) == 0)
126 return map[i].signal_type;
132 static void __handle_size_info_callback(struct cb_info *cb_info,
133 const char *pkgid, const char *val)
135 pkg_size_info_t size_info;
139 pkgmgr_total_pkg_size_info_receive_cb callback;
141 snprintf(buf, sizeof(buf), "%s", val);
143 DBG("%s, %s", pkgid, val);
145 token = strtok_r(buf, ":", &saveptr);
147 ERR("failed to parse size info");
150 size_info.data_size = atoll(token);
151 token = strtok_r(NULL, ":", &saveptr);
153 ERR("failed to parse size info");
156 size_info.cache_size = atoll(token);
157 token = strtok_r(NULL, ":", &saveptr);
159 ERR("failed to parse size info");
162 size_info.app_size = atoll(token);
163 token = strtok_r(NULL, ":", &saveptr);
165 ERR("failed to parse size info");
168 size_info.ext_data_size = atoll(token);
169 token = strtok_r(NULL, ":", &saveptr);
171 ERR("failed to parse size info");
174 size_info.ext_cache_size = atoll(token);
175 token = strtok_r(NULL, ":", &saveptr);
177 ERR("failed to parse size info");
180 size_info.ext_app_size = atoll(token);
182 DBG("data: %lld, cache: %lld, app: %lld, ext_data: %lld, "
183 "ext_cache: %lld, ext_app: %lld",
184 size_info.data_size, size_info.cache_size,
185 size_info.app_size, size_info.ext_data_size,
186 size_info.ext_cache_size, size_info.ext_app_size);
188 if (strcmp(pkgid, PKG_SIZE_INFO_TOTAL) == 0) {
189 callback = (pkgmgr_total_pkg_size_info_receive_cb)
190 cb_info->size_info_cb;
191 callback(cb_info->client, &size_info, cb_info->data);
193 cb_info->size_info_cb(cb_info->client, pkgid, &size_info,
198 static void __handle_pkg_signal(const gchar *signal_name,
199 GVariant *parameters, gpointer user_data)
203 char *pkg_type = NULL;
208 struct cb_info *cb_info = (struct cb_info *)user_data;
209 GVariantIter *iter = NULL;
212 g_variant_get(parameters, "(u&sa(sss)&s&s)", &target_uid, &req_id, &iter,
214 while (g_variant_iter_loop(iter, "(&s&s&s)", &pkgid, &appid, &pkg_type)) {
215 if (cb_info->req_key) {
216 if (strcmp(cb_info->req_key, req_id) != 0)
219 signal_type = __get_signal_type(signal_name);
220 if (signal_type < 0 || !(cb_info->status_type & signal_type)) {
221 g_variant_iter_free(iter);
226 /* each cb_data can only has one callback */
227 if (cb_info->event_cb) {
228 cb_info->event_cb(target_uid, cb_info->req_id,
229 pkg_type, pkgid, key, val, NULL, cb_info->data);
230 } else if (cb_info->app_event_cb && strcmp(appid, "") != 0) {
231 cb_info->app_event_cb(target_uid, cb_info->req_id,
232 pkg_type, pkgid, appid, key, val, NULL,
234 } else if (cb_info->size_info_cb) {
235 __handle_size_info_callback(cb_info, pkgid, val);
238 /* TODO: unsubscribe request callback */
240 g_variant_iter_free(iter);
243 static void __handle_res_copy_event_signal(const gchar *signal_name,
244 GVariant *parameters, gpointer user_data)
250 struct cb_info *cb_info = (struct cb_info *)user_data;
252 GVariant *extra_param = NULL;
253 pkgmgr_res_event_info_t event_info;
255 if (!cb_info->res_copy_event_cb)
258 g_variant_get(parameters, "(u&s&s&sv)", &target_uid, &req_id, &pkgid, &status, &extra_param);
259 if (!g_variant_type_equal(G_VARIANT_TYPE("(i)"),
260 g_variant_get_type(extra_param))) {
261 ERR("invalid extra parameter");
262 g_variant_unref(extra_param);
265 if (cb_info->req_key) {
266 if (strcmp(cb_info->req_key, req_id) != 0) {
267 g_variant_unref(extra_param);
271 signal_type = __get_signal_type(signal_name);
272 if (signal_type < 0 || !(cb_info->status_type & signal_type)) {
273 g_variant_unref(extra_param);
278 g_variant_get(extra_param, "(i)", &event_info.error_code);
279 cb_info->res_copy_event_cb(target_uid, cb_info->req_id, pkgid, signal_name,
280 status, &event_info, cb_info->data);
281 g_variant_unref(extra_param);
284 static void __signal_handler(GDBusConnection *conn, const gchar *sender_name,
285 const gchar *object_path, const gchar *interface_name,
286 const gchar *signal_name, GVariant *parameters,
289 if (g_variant_type_equal(G_VARIANT_TYPE("(usa(sss)ss)"),
290 g_variant_get_type(parameters))) {
291 __handle_pkg_signal(signal_name, parameters, user_data);
292 } else if (!strcmp(signal_name, PKGMGR_INSTALLER_RES_COPY_EVENT_STR) ||
293 !strcmp(signal_name, PKGMGR_INSTALLER_RES_REMOVE_EVENT_STR) ||
294 !strcmp(signal_name, PKGMGR_INSTALLER_RES_UNINSTALL_EVENT_STR)) {
295 __handle_res_copy_event_signal(signal_name, parameters, user_data);
299 static void __set_signal_list(int event, GList **signal_list)
302 if (event == PKGMGR_CLIENT_STATUS_ALL)
305 for (i = 0; map[i].signal_str != NULL; i++) {
306 if (event & map[i].signal_type)
307 *signal_list = g_list_append(*signal_list,
308 (char *)map[i].signal_str);
312 static int __subscribe_signal(struct pkgmgr_client_t *pc,
313 struct cb_info *cb_info, const char *signal)
315 guint sid = g_dbus_connection_signal_subscribe(pc->conn, NULL,
316 PKGMGR_INSTALLER_DBUS_INTERFACE, signal,
317 PKGMGR_INSTALLER_DBUS_OBJECT_PATH, NULL,
318 G_DBUS_SIGNAL_FLAGS_NONE, __signal_handler,
319 (gpointer)cb_info, NULL);
321 ERR("failed to subscribe singal");
322 return PKGMGR_R_ERROR;
324 cb_info->sid_list = g_list_append(cb_info->sid_list,
325 GUINT_TO_POINTER(sid));
330 int pkgmgr_client_connection_set_callback(struct pkgmgr_client_t *pc,
331 struct cb_info *cb_info)
333 GList *signal_list = NULL;
334 GList *tmp_list = NULL;
337 __set_signal_list(pc->status_type, &signal_list);
339 if (g_list_length(signal_list) == 0)
340 return __subscribe_signal(pc, cb_info, NULL);
342 for (tmp_list = signal_list; tmp_list != NULL;
343 tmp_list = g_list_next(tmp_list)) {
344 signal_type = (char *)tmp_list->data;
345 ret = __subscribe_signal(pc, cb_info, signal_type);
347 g_list_free(signal_list);
348 return PKGMGR_R_ERROR;
352 g_list_free(signal_list);
356 void pkgmgr_client_connection_unset_callback(struct pkgmgr_client_t *pc,
357 struct cb_info *cb_info)
361 for (tmp = cb_info->sid_list; tmp != NULL; tmp = g_list_next(tmp)) {
362 tmp_sid = GPOINTER_TO_UINT(tmp->data);
363 g_dbus_connection_signal_unsubscribe(pc->conn, tmp_sid);
367 int pkgmgr_client_connection_send_request(struct pkgmgr_client_t *pc,
368 const char *method, GVariant *params, GVariant **result)
370 GError *error = NULL;
374 int ret = PKGMGR_R_ECOMM;
376 /* convert floating ref into normal ref */
377 g_variant_ref_sink(params);
380 proxy = g_dbus_proxy_new_sync(pc->conn,
381 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
382 NULL, PKGMGR_DBUS_SERVICE,
383 PKGMGR_DBUS_OBJECT_PATH,
384 PKGMGR_DBUS_INTERFACE, NULL, &error);
386 ERR("failed to get proxy object, sleep and retry[%s]",
390 usleep(CONNECTION_WAIT_USEC);
395 r = g_dbus_proxy_call_sync(proxy, method, params,
396 G_DBUS_CALL_FLAGS_NONE,
397 CONNECTION_TIMEOUT_MSEC, NULL, &error);
398 g_object_unref(proxy);
399 if (error && error->code == G_DBUS_ERROR_ACCESS_DENIED) {
400 ERR("failed to send request, privilege denied[%s]",
403 ret = PKGMGR_R_EPRIV;
412 ERR("failed to send request, sleep and retry[%s]",
416 usleep(CONNECTION_WAIT_USEC);
418 } while (retry_cnt <= CONNECTION_RETRY_MAX);
420 /* decrease ref count to 0 to free resource */
421 g_variant_unref(params);