2 * Copyright (c) 2011 - 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.
28 #include <pkgmgr-info.h>
30 #include "app_context.h"
31 #include "app_manager.h"
32 #include "app_manager_internal.h"
38 #define LOG_TAG "CAPI_APPFW_APP_MANAGER"
42 static int app_context_create(const char *app_id, pid_t pid, const char *pkg_id, app_state_e app_state, bool is_sub_app, app_context_h *app_context);
44 struct app_context_s {
48 app_state_e app_state;
52 typedef struct _foreach_context_ {
53 app_manager_app_context_cb callback;
58 typedef struct _retrieval_context_ {
62 app_state_e app_state;
65 const char *instance_id;
66 } retrieval_context_s;
68 static app_manager_app_context_status_cb _status_cb;
70 static app_state_e app_context_get_app_status(int status)
72 app_state_e app_state;
76 app_state = APP_STATE_FOREGROUND;
78 case STATUS_LAUNCHING:
80 app_state = APP_STATE_BACKGROUND;
83 app_state = APP_STATE_SERVICE;
85 case STATUS_TERMINATE:
86 app_state = APP_STATE_TERMINATED;
89 app_state = APP_STATE_UNDEFINED;
96 static int app_context_foreach_app_context_cb(const aul_app_info *aul_app_context, void *cb_data)
98 foreach_context_s *foreach_context = cb_data;
99 app_context_h app_context;
100 app_state_e app_state;
101 bool is_sub_app = false;
103 if (foreach_context == NULL) {
104 app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
108 if (foreach_context->iteration == true) {
109 app_state = app_context_get_app_status(aul_app_context->status);
111 if (aul_app_context->is_sub_app)
114 if (app_context_create(aul_app_context->appid,
115 aul_app_context->pid,
116 aul_app_context->pkgid,
119 &app_context) == APP_MANAGER_ERROR_NONE) {
120 foreach_context->iteration = foreach_context->callback(app_context, foreach_context->user_data);
121 app_context_destroy(app_context);
128 int app_context_foreach_app_context(app_manager_app_context_cb callback, void *user_data)
130 foreach_context_s foreach_context = {
131 .callback = callback,
132 .user_data = user_data,
136 if (callback == NULL)
137 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
139 if (aul_app_get_running_app_info(app_context_foreach_app_context_cb, &foreach_context) != AUL_R_OK)
140 return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, NULL);
142 return APP_MANAGER_ERROR_NONE;
145 static int app_context_foreach_running_app_context_cb(const aul_app_info *aul_app_context, void *cb_data)
147 foreach_context_s *foreach_context = cb_data;
148 app_context_h app_context;
149 app_state_e app_state;
150 bool is_sub_app = false;
152 if (foreach_context == NULL) {
153 app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
157 if (foreach_context->iteration == true) {
158 app_state = app_context_get_app_status(aul_app_context->status);
160 if (aul_app_context->is_sub_app)
163 if (app_context_create(aul_app_context->appid,
164 aul_app_context->pid,
165 aul_app_context->pkgid,
168 &app_context) == APP_MANAGER_ERROR_NONE) {
169 foreach_context->iteration = foreach_context->callback(app_context, foreach_context->user_data);
170 app_context_destroy(app_context);
177 int app_context_foreach_running_app_context(app_manager_app_context_cb callback, void *user_data)
180 foreach_context_s foreach_context = {
181 .callback = callback,
182 .user_data = user_data,
186 if (callback == NULL)
187 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
189 ret = aul_app_get_all_running_app_info(app_context_foreach_running_app_context_cb, &foreach_context);
191 return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, NULL);
193 return APP_MANAGER_ERROR_NONE;
196 static int app_context_retrieve_app_context(const aul_app_info *aul_app_context, void *cb_data)
198 retrieval_context_s *retrieval_context = cb_data;
199 app_state_e app_state;
201 if (aul_app_context != NULL && retrieval_context != NULL && retrieval_context->matched == false) {
202 if (retrieval_context->instance_id &&
203 !strcmp(aul_app_context->instance_id, retrieval_context->instance_id) &&
204 !strcmp(aul_app_context->appid, retrieval_context->app_id)) {
205 app_state = app_context_get_app_status(aul_app_context->status);
207 retrieval_context->pid = aul_app_context->pid;
208 retrieval_context->pkg_id = strdup(aul_app_context->pkgid);
209 retrieval_context->app_state = app_state;
210 if (aul_app_context->is_sub_app)
211 retrieval_context->is_sub_app = true;
212 retrieval_context->matched = true;
213 } else if (retrieval_context->instance_id == NULL &&
214 !strcmp(aul_app_context->appid, retrieval_context->app_id)) {
215 app_state = app_context_get_app_status(aul_app_context->status);
217 retrieval_context->pid = aul_app_context->pid;
218 retrieval_context->pkg_id = strdup(aul_app_context->pkgid);
219 retrieval_context->app_state = app_state;
220 if (aul_app_context->is_sub_app)
221 retrieval_context->is_sub_app = true;
222 retrieval_context->matched = true;
229 int app_context_get_app_context(const char *app_id, app_context_h *app_context)
232 retrieval_context_s retrieval_context = {
236 .app_state = APP_STATE_UNDEFINED,
242 if (app_id == NULL || app_context == NULL)
243 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
245 if (aul_app_is_running(app_id) == 0)
246 return app_manager_error(APP_MANAGER_ERROR_NO_SUCH_APP, __FUNCTION__, NULL);
248 aul_app_get_running_app_info(app_context_retrieve_app_context, &retrieval_context);
250 if (retrieval_context.matched == false)
251 return app_manager_error(APP_MANAGER_ERROR_NO_SUCH_APP, __FUNCTION__, NULL);
253 ret = app_context_create(retrieval_context.app_id,
254 retrieval_context.pid,
255 retrieval_context.pkg_id,
256 retrieval_context.app_state,
257 retrieval_context.is_sub_app,
259 free(retrieval_context.pkg_id);
264 static int app_context_create(const char *app_id, pid_t pid, const char *pkg_id, app_state_e app_state, bool is_sub_app, app_context_h *app_context)
266 app_context_h app_context_created;
268 if (app_id == NULL || pid <= 0 || pkg_id == NULL || app_context == NULL)
269 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
271 app_context_created = calloc(1, sizeof(struct app_context_s));
272 if (app_context_created == NULL)
273 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
275 app_context_created->app_id = strdup(app_id);
276 if (app_context_created->app_id == NULL) {
277 free(app_context_created);
278 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
281 app_context_created->pkg_id = strdup(pkg_id);
282 if (app_context_created->pkg_id == NULL) {
283 free(app_context_created->app_id);
284 free(app_context_created);
285 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
288 app_context_created->pid = pid;
289 app_context_created->app_state = app_state;
290 app_context_created->is_sub_app = is_sub_app;
292 *app_context = app_context_created;
294 return APP_MANAGER_ERROR_NONE;
297 API int app_context_destroy(app_context_h app_context)
299 if (app_context == NULL)
300 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
302 free(app_context->app_id);
303 free(app_context->pkg_id);
306 return APP_MANAGER_ERROR_NONE;
309 API int app_context_get_package(app_context_h app_context, char **package)
311 dlog_print(DLOG_WARN, LOG_TAG, "DEPRECATION WARNING: app_context_get_package() is deprecated and will be removed from next release. Use app_context_get_app_id() instead.");
312 /* TODO: this function must be deprecated */
313 return app_context_get_app_id(app_context, package);
317 API int app_context_get_app_id(app_context_h app_context, char **app_id)
321 if (app_context == NULL || app_id == NULL)
322 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
324 app_id_dup = strdup(app_context->app_id);
325 if (app_id_dup == NULL)
326 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
328 *app_id = app_id_dup;
330 return APP_MANAGER_ERROR_NONE;
333 API int app_context_get_pid(app_context_h app_context, pid_t *pid)
335 if (app_context == NULL || pid == NULL)
336 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
338 *pid = app_context->pid;
340 return APP_MANAGER_ERROR_NONE;
343 API int app_context_get_package_id(app_context_h app_context, char **pkg_id)
347 if (app_context == NULL || pkg_id == NULL)
348 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
350 pkg_id_dup = strdup(app_context->pkg_id);
351 if (pkg_id_dup == NULL)
352 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
354 *pkg_id = pkg_id_dup;
356 return APP_MANAGER_ERROR_NONE;
359 API int app_context_get_app_state(app_context_h app_context, app_state_e *state)
361 if (app_context == NULL || state == NULL)
362 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
364 *state = app_context->app_state;
366 return APP_MANAGER_ERROR_NONE;
369 API int app_context_is_terminated(app_context_h app_context, bool *terminated)
371 char appid[APPID_MAX] = {0, };
373 if (app_context == NULL || terminated == NULL)
374 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
376 if (aul_app_is_running(app_context->app_id) == 1) {
379 if (aul_app_get_appid_bypid(app_context->pid, appid, sizeof(appid)) == AUL_R_OK)
385 return APP_MANAGER_ERROR_NONE;
388 API int app_context_is_equal(app_context_h lhs, app_context_h rhs, bool *equal)
390 if (lhs == NULL || rhs == NULL || equal == NULL)
391 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
393 if (!strcmp(lhs->app_id, rhs->app_id) && lhs->pid == rhs->pid)
398 return APP_MANAGER_ERROR_NONE;
401 API int app_context_is_sub_app(app_context_h app_context, bool *is_sub_app)
403 if (app_context == NULL || is_sub_app == NULL)
404 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
406 *is_sub_app = app_context->is_sub_app;
408 return APP_MANAGER_ERROR_NONE;
411 API int app_context_clone(app_context_h *clone, app_context_h app_context)
415 if (clone == NULL || app_context == NULL)
416 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
418 retval = app_context_create(app_context->app_id,
421 app_context->app_state,
422 app_context->is_sub_app,
424 if (retval != APP_MANAGER_ERROR_NONE)
425 return app_manager_error(retval, __FUNCTION__, NULL);
427 return APP_MANAGER_ERROR_NONE;
430 typedef struct _event_cb_context_ {
431 GHashTable *pid_table;
432 app_manager_app_context_event_cb callback;
434 } event_cb_context_s;
436 static pthread_mutex_t event_cb_context_mutex = PTHREAD_MUTEX_INITIALIZER;
437 static event_cb_context_s *event_cb_context = NULL;
439 static void app_context_lock_event_cb_context()
441 pthread_mutex_lock(&event_cb_context_mutex);
444 static void app_context_unlock_event_cb_context()
446 pthread_mutex_unlock(&event_cb_context_mutex);
449 static bool app_context_load_all_app_context_cb_locked(app_context_h app_context, void *user_data)
451 app_context_h app_context_cloned;
453 if (app_context_clone(&app_context_cloned, app_context) == APP_MANAGER_ERROR_NONE) {
454 SECURE_LOGI("[%s] app_id(%s), pid(%d)", __FUNCTION__, app_context->app_id, app_context->pid);
456 if (event_cb_context != NULL && event_cb_context->pid_table != NULL) {
457 g_hash_table_insert(event_cb_context->pid_table, GINT_TO_POINTER(&(app_context_cloned->pid)), app_context_cloned);
459 app_context_destroy(app_context_cloned);
460 app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "invalid callback context");
467 static void app_context_pid_table_entry_destroyed_cb(void *data)
469 app_context_h app_context = data;
471 if (app_context != NULL)
472 app_context_destroy(app_context);
475 static int app_context_get_pkgid_by_appid(const char *app_id, char **pkg_id)
477 pkgmgrinfo_appinfo_h appinfo;
480 if (app_id == NULL || pkg_id == NULL)
481 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
483 if (pkgmgrinfo_appinfo_get_usr_appinfo(app_id, getuid(), &appinfo) < 0)
484 return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "fail to get appinfo");
486 if (pkgmgrinfo_appinfo_get_pkgid(appinfo, &pkg_id_dup) < 0) {
487 pkgmgrinfo_appinfo_destroy_appinfo(appinfo);
488 return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "fail to get pkgid");
491 *pkg_id = strdup(pkg_id_dup);
493 pkgmgrinfo_appinfo_destroy_appinfo(appinfo);
494 return APP_MANAGER_ERROR_NONE;
497 static int app_context_launched_event_cb(pid_t pid, const char *app_id, void *data)
499 app_context_h app_context = NULL;
502 if (pid < 0 || app_id == NULL)
503 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
505 if (app_context_get_pkgid_by_appid(app_id, &pkg_id) < 0)
506 return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "no such pkg_id");
508 app_context_lock_event_cb_context();
510 if (app_context_create(app_id, pid, pkg_id, APP_STATE_UNDEFINED, false, &app_context) == APP_MANAGER_ERROR_NONE) {
511 if (event_cb_context != NULL && event_cb_context->pid_table != NULL) {
512 g_hash_table_insert(event_cb_context->pid_table, GINT_TO_POINTER(&(app_context->pid)), app_context);
513 event_cb_context->callback(app_context, APP_CONTEXT_EVENT_LAUNCHED, event_cb_context->user_data);
515 app_context_destroy(app_context);
516 app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "invalid callback context");
520 app_context_unlock_event_cb_context();
526 static int app_context_terminated_event_cb(pid_t pid, void *data)
528 app_context_h app_context;
529 int lookup_key = pid;
531 app_context_lock_event_cb_context();
533 if (event_cb_context != NULL && event_cb_context->pid_table != NULL) {
534 app_context = g_hash_table_lookup(event_cb_context->pid_table, GINT_TO_POINTER(&lookup_key));
536 if (app_context != NULL) {
537 event_cb_context->callback(app_context, APP_CONTEXT_EVENT_TERMINATED, event_cb_context->user_data);
538 g_hash_table_remove(event_cb_context->pid_table, GINT_TO_POINTER(&(app_context->pid)));
541 app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "invalid callback context");
544 app_context_unlock_event_cb_context();
549 int app_context_set_event_cb(app_manager_app_context_event_cb callback, void *user_data)
551 if (callback == NULL)
552 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
554 app_context_lock_event_cb_context();
556 if (event_cb_context == NULL) {
557 event_cb_context = calloc(1, sizeof(event_cb_context_s));
559 if (event_cb_context == NULL) {
560 app_context_unlock_event_cb_context();
561 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
564 event_cb_context->pid_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, app_context_pid_table_entry_destroyed_cb);
565 if (event_cb_context->pid_table == NULL) {
566 free(event_cb_context);
567 event_cb_context = NULL;
568 app_context_unlock_event_cb_context();
569 return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "failed to initialize pid-table");
572 app_context_foreach_app_context(app_context_load_all_app_context_cb_locked, NULL);
574 aul_listen_app_dead_signal(app_context_terminated_event_cb, NULL);
575 aul_listen_app_launch_signal_v2(app_context_launched_event_cb, NULL);
579 event_cb_context->callback = callback;
580 event_cb_context->user_data = user_data;
582 app_context_unlock_event_cb_context();
584 return APP_MANAGER_ERROR_NONE;
587 void app_context_unset_event_cb(void)
589 app_context_lock_event_cb_context();
591 if (event_cb_context != NULL) {
592 /* aul_listen_app_dead_signal(NULL, NULL); */
593 /* aul_listen_app_launch_signal(NULL, NULL); */
595 g_hash_table_destroy(event_cb_context->pid_table);
596 free(event_cb_context);
597 event_cb_context = NULL;
600 app_context_unlock_event_cb_context();
603 static int app_context_status_cb(const char *appid, const char *pkgid, int pid, int status, int is_subapp, void *data)
605 app_context_h app_context = NULL;
607 app_context_status_e context_status;
610 state = app_context_get_app_status(status);
611 if (state == APP_STATE_TERMINATED)
612 context_status = APP_CONTEXT_STATUS_TERMINATED;
614 context_status = APP_CONTEXT_STATUS_LAUNCHED;
616 ret = app_context_create(appid, pid, pkgid, state, is_subapp, &app_context);
617 if (ret != APP_MANAGER_ERROR_NONE)
618 return app_manager_error(ret, __FUNCTION__, NULL);
620 _status_cb(app_context, context_status, data);
621 app_context_destroy(app_context);
623 return APP_MANAGER_ERROR_NONE;
626 int app_context_set_status_cb(app_manager_app_context_status_cb callback, const char *appid, void *user_data)
630 if (callback == NULL || appid == NULL)
631 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
633 _status_cb = callback;
635 ret = aul_listen_app_status(appid, app_context_status_cb, user_data);
638 ret = APP_MANAGER_ERROR_NONE;
641 ret = APP_MANAGER_ERROR_INVALID_PARAMETER;
644 ret = APP_MANAGER_ERROR_IO_ERROR;
651 int app_context_get_app_context_by_instance_id(const char *app_id, const char *instance_id, app_context_h *app_context)
654 retrieval_context_s retrieval_context = {
658 .app_state = APP_STATE_UNDEFINED,
661 .instance_id = instance_id
664 if (app_id == NULL || instance_id == NULL || app_context == NULL)
665 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
667 aul_app_get_running_app_instance_info(app_context_retrieve_app_context, &retrieval_context);
668 if (retrieval_context.matched == false)
669 return app_manager_error(APP_MANAGER_ERROR_NO_SUCH_APP, __FUNCTION__, NULL);
671 ret = app_context_create(retrieval_context.app_id,
672 retrieval_context.pid,
673 retrieval_context.pkg_id,
674 retrieval_context.app_state,
675 retrieval_context.is_sub_app,
677 free(retrieval_context.pkg_id);