2 * Copyright 2016 Samsung Electronics Co., Ltd
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.
22 #include <package-manager.h>
24 #include "service_common.h"
29 #define PKGMGR_EVENT_MIN PKGMGR_EVENT_DOWNLOAD
30 #define PKGMGR_EVENT_MAX PKGMGR_EVENT_APP_DISABLE
37 enum pkgmgr_event_type type;
38 enum pkgmgr_status status;
42 int (*cb)(uid_t uid, const char *pkgname, enum pkgmgr_status status, double value, void *data);
47 pkgmgr_client *listen_pc;
55 static GList *event_list[PKGMGR_EVENT_MAX + 1];
57 static inline void invoke_callback(uid_t uid, const char *pkgname, struct item *item, double value)
60 struct event_item *e_item;
62 for (l = event_list[item->type]; l != NULL; l = g_list_next(l)) {
63 e_item = (struct event_item *)g_list_nth_data(l, 0);
65 e_item->cb(uid, pkgname, item->status, value, e_item->data);
69 static inline int is_valid_status(struct item *item, const char *status)
71 const char *expected_status;
74 case PKGMGR_EVENT_DOWNLOAD:
75 expected_status = "download";
77 case PKGMGR_EVENT_UNINSTALL:
78 expected_status = "uninstall";
80 case PKGMGR_EVENT_INSTALL:
81 expected_status = "install";
83 case PKGMGR_EVENT_UPDATE:
84 expected_status = "update";
86 case PKGMGR_EVENT_RECOVER:
87 expected_status = "recover";
89 case PKGMGR_EVENT_APP_ENABLE:
90 expected_status = "app_enable_app";
92 case PKGMGR_EVENT_APP_DISABLE:
93 expected_status = "app_disable_app";
99 return !strcasecmp(status, expected_status);
102 static struct item *find_item(const char *pkgname, uid_t uid)
108 ERR("Invalid pkgname");
112 for (l = s_info.item_list; l != NULL; l = g_list_next(l)) {
113 item = g_list_nth_data(l, 0);
114 if (uid != item->uid || strcmp(item->pkgname, pkgname))
120 DBG("Package [%s] is not found", pkgname);
124 static int start_cb(uid_t uid, const char *pkgname, const char *val, void *data)
128 INFO("pkgname[%s] val[%s]", pkgname, val);
130 item = calloc(1, sizeof(*item));
132 ERR("calloc [%d]", errno);
133 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
136 item->pkgname = strdup(pkgname);
137 if (!item->pkgname) {
138 ERR("strdup [%d]", errno);
140 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
144 item->status = PKGMGR_STATUS_START;
146 if (!strcasecmp(val, "download")) {
147 item->type = PKGMGR_EVENT_DOWNLOAD;
148 } else if (!strcasecmp(val, "uninstall")) {
149 item->type = PKGMGR_EVENT_UNINSTALL;
150 } else if (!strcasecmp(val, "install")) {
151 item->type = PKGMGR_EVENT_INSTALL;
152 } else if (!strcasecmp(val, "update")) {
153 item->type = PKGMGR_EVENT_UPDATE;
154 } else if (!strcasecmp(val, "recover")) {
155 item->type = PKGMGR_EVENT_RECOVER;
156 } else if (!strcasecmp(val, "enable_app")) {
157 item->type = PKGMGR_EVENT_APP_ENABLE;
158 } else if (!strcasecmp(val, "disable_app")) {
159 item->type = PKGMGR_EVENT_APP_DISABLE;
163 ERR("Invalid val [%s]", val);
164 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
166 s_info.item_list = g_list_append(s_info.item_list, item);
168 invoke_callback(uid, pkgname, item, 0.0f);
169 return SERVICE_COMMON_ERROR_NONE;
172 static int icon_path_cb(uid_t uid, const char *pkgname, const char *val, void *data)
176 DBG("pkgname[%s] val[%s]", pkgname, val);
178 item = find_item(pkgname, uid);
180 return SERVICE_COMMON_ERROR_NOT_EXIST;
185 item->icon = strdup(val);
187 ERR("strdup [%d]", errno);
188 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
191 return SERVICE_COMMON_ERROR_NONE;
194 static int command_cb(uid_t uid, const char *pkgname, const char *val, void *data)
198 DBG("pkgname[%s] val[%s]", pkgname, val);
200 item = find_item(pkgname, uid);
202 return SERVICE_COMMON_ERROR_NOT_EXIST;
204 if (!is_valid_status(item, val)) {
205 DBG("Invalid status[%d] val[%s]", item->type, val);
206 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
209 item->status = PKGMGR_STATUS_COMMAND;
210 invoke_callback(uid, pkgname, item, 0.0f);
211 return SERVICE_COMMON_ERROR_NONE;
214 static int error_cb(uid_t uid, const char *pkgname, const char *val, void *data)
219 INFO("pkgname[%s] val[%s]", pkgname, val);
221 item = find_item(pkgname, uid);
223 return SERVICE_COMMON_ERROR_NOT_EXIST;
225 item->status = PKGMGR_STATUS_ERROR;
226 invoke_callback(uid, pkgname, item, 0.0f);
227 return SERVICE_COMMON_ERROR_NONE;
230 static int change_pkgname_cb(uid_t uid, const char *pkgname, const char *val, void *data)
235 INFO("pkgname[%s] val[%s]", pkgname, val);
237 item = find_item(pkgname, uid);
239 return SERVICE_COMMON_ERROR_NOT_EXIST;
241 new_pkgname = strdup(val);
243 ERR("strdup: %d", errno);
244 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
248 item->pkgname = new_pkgname;
249 return SERVICE_COMMON_ERROR_NONE;
252 static int download_cb(uid_t uid, const char *pkgname, const char *val, void *data)
258 INFO("pkgname[%s] val[%s]", pkgname, val);
260 item = find_item(pkgname, uid);
262 DBG("ITEM is not started from the start_cb");
263 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
266 if (item->type != PKGMGR_EVENT_DOWNLOAD) {
267 DBG("TYPE is not \"download\" [%d]", item->type);
268 item->type = PKGMGR_EVENT_DOWNLOAD;
271 switch (item->status) {
272 case PKGMGR_STATUS_START:
273 case PKGMGR_STATUS_COMMAND:
274 item->status = PKGMGR_STATUS_PROCESSING;
275 case PKGMGR_STATUS_PROCESSING:
278 ERR("Invalid status, pkgname[%s] val[%s]", pkgname, val);
279 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
283 if (sscanf(val, "%lf", &value) != 1)
284 value = (double)SERVICE_COMMON_ERROR_INVALID_PARAMETER;
286 value = (double)SERVICE_COMMON_ERROR_INVALID_PARAMETER;
289 invoke_callback(uid, pkgname, item, value);
290 return SERVICE_COMMON_ERROR_NONE;
293 static int progress_cb(uid_t uid, const char *pkgname, const char *val, void *data)
299 item = find_item(pkgname, uid);
301 ERR("ITEM is not started from the start_cb");
302 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
305 switch (item->status) {
306 case PKGMGR_STATUS_START:
307 case PKGMGR_STATUS_COMMAND:
308 item->status = PKGMGR_STATUS_PROCESSING;
309 case PKGMGR_STATUS_PROCESSING:
312 ERR("Invalid status, pkgname[%s] val[%s]", pkgname, val);
313 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
317 if (sscanf(val, "%lf", &value) != 1)
318 value = (double)SERVICE_COMMON_ERROR_INVALID_PARAMETER;
320 value = (double)SERVICE_COMMON_ERROR_INVALID_PARAMETER;
323 invoke_callback(uid, pkgname, item, value);
324 return SERVICE_COMMON_ERROR_NONE;
327 static int end_cb(uid_t uid, const char *pkgname, const char *val, void *data)
331 DBG("[%s] %s", pkgname, val);
333 item = find_item(pkgname, uid);
335 return SERVICE_COMMON_ERROR_NOT_EXIST;
337 item->status = !strcasecmp(val, "ok") ? PKGMGR_STATUS_END : PKGMGR_STATUS_ERROR;
339 invoke_callback(uid, pkgname, item, 0.0f);
341 s_info.item_list = g_list_remove(s_info.item_list, item);
345 return SERVICE_COMMON_ERROR_NONE;
348 static struct pkgmgr_handler {
350 int (*func)(uid_t uid, const char *package, const char *val, void *data);
352 { "install_percent", progress_cb },
353 { "download_percent", download_cb },
354 { "start", start_cb },
356 { "change_pkg_name", change_pkgname_cb },
357 { "icon_path", icon_path_cb },
358 { "command", command_cb },
359 { "error", error_cb },
363 static int status_cb(uid_t target_uid, int req_id, const char *type,
364 const char *pkgname, const char *key, const char *val,
365 const void *pmsg, void *data)
370 for (i = 0; handler[i].key; i++) {
371 if (strcasecmp(key, handler[i].key))
374 ret = handler[i].func(target_uid, pkgname, val, data);
376 DBG("REQ[%d] UID[%d] pkgname[%s] type[%s] key[%s] val[%s] ret[%d]",
377 req_id, target_uid, pkgname, type, key, val, ret);
381 return SERVICE_COMMON_ERROR_NONE;
384 static int app_status_cb(uid_t target_uid, int req_id, const char *pkg_type,
385 const char *pkgid, const char *appid, const char *key, const char *val,
386 const void *pmsg, void *data)
391 for (i = 0; handler[i].key; i++) {
392 if (strcasecmp(key, handler[i].key))
395 ret = handler[i].func(target_uid, appid, val, data);
397 DBG("REQ[%d] UID[%d] appid[%s] type[%s] key[%s] val[%s] ret[%d]",
398 req_id, target_uid, appid, pkg_type, key, val, ret);
402 return SERVICE_COMMON_ERROR_NONE;
405 static void __free_event_data(gpointer data)
407 struct event_item *item = (struct event_item *)data;
413 static void __free_item_data(gpointer data)
415 struct item *ctx = (struct item *)data;
426 HAPI int pkgmgr_init(void)
428 if (s_info.listen_pc)
429 return SERVICE_COMMON_ERROR_ALREADY_EXIST;
431 s_info.listen_pc = pkgmgr_client_new(PC_LISTENING);
432 if (!s_info.listen_pc)
433 return SERVICE_COMMON_ERROR_FAULT;
435 /* the pkgmgr api returns an id greater than 1 */
436 if (pkgmgr_client_listen_status(s_info.listen_pc, status_cb, NULL) <= 0)
437 return SERVICE_COMMON_ERROR_FAULT;
439 if (pkgmgr_client_listen_app_status(s_info.listen_pc, app_status_cb, NULL) <= 0)
440 return SERVICE_COMMON_ERROR_FAULT;
442 return SERVICE_COMMON_ERROR_NONE;
445 HAPI int pkgmgr_fini(void)
449 if (!s_info.listen_pc)
450 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
452 if (pkgmgr_client_free(s_info.listen_pc) != PKGMGR_R_OK)
453 return SERVICE_COMMON_ERROR_FAULT;
455 s_info.listen_pc = NULL;
457 for (i = PKGMGR_EVENT_MIN; i <= PKGMGR_EVENT_MAX; i++)
458 g_list_free_full(event_list[i], __free_event_data);
460 g_list_free_full(s_info.item_list, __free_item_data);
462 return SERVICE_COMMON_ERROR_NONE;
465 HAPI int pkgmgr_add_event_callback(enum pkgmgr_event_type type, int (*cb)(uid_t uid, const char *pkgname, enum pkgmgr_status status, double value, void *data), void *data)
467 struct event_item *item;
469 item = calloc(1, sizeof(*item));
471 ERR("calloc [%d]", errno);
472 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
478 event_list[type] = g_list_prepend(event_list[type], item);
480 return SERVICE_COMMON_ERROR_NONE;
483 HAPI void *pkgmgr_del_event_callback(enum pkgmgr_event_type type, int (*cb)(uid_t uid, const char *pkgname, enum pkgmgr_status status, double value, void *data), void *data)
485 struct event_item *item;
489 for (l = event_list[type]; l != NULL; l = g_list_next(l)) {
490 item = g_list_nth_data(l, 0);
491 if (item->cb == cb && item->data == data) {
492 event_list[type] = g_list_remove(event_list[type], item);