Delete privilege checking routine
[platform/core/api/app-manager.git] / src / app_context.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <pthread.h>
23
24 #include <glib.h>
25
26 #include <aul.h>
27 #include <dlog.h>
28 #include <pkgmgr-info.h>
29
30 #include "app_context.h"
31 #include "app_manager.h"
32 #include "app_manager_internal.h"
33
34 #ifdef LOG_TAG
35 #undef LOG_TAG
36 #endif
37
38 #define LOG_TAG "CAPI_APPFW_APP_MANAGER"
39
40 #define APPID_MAX 128
41
42 static int app_context_create(const char *app_id, pid_t pid, char *pkg_id, app_state_e app_state, bool is_sub_app, app_context_h *app_context);
43
44 struct app_context_s {
45         char *app_id;
46         pid_t pid;
47         char *pkg_id;
48         app_state_e app_state;
49         bool is_sub_app;
50 };
51
52 typedef struct _foreach_context_ {
53         app_manager_app_context_cb callback;
54         void *user_data;
55         bool iteration;
56 } foreach_context_s;
57
58 typedef struct _retrieval_context_ {
59         const char *app_id;
60         pid_t pid;
61         char *pkg_id;
62         app_state_e app_state;
63         bool is_sub_app;
64         bool matched;
65 } retrieval_context_s;
66
67 static app_state_e app_context_get_app_status(int status)
68 {
69         app_state_e app_state;
70
71         switch (status) {
72         case STATUS_VISIBLE:
73                 app_state = APP_STATE_FOREGROUND;
74                 break;
75         case STATUS_LAUNCHING:
76         case STATUS_BG:
77                 app_state = APP_STATE_BACKGROUND;
78                 break;
79         case STATUS_SERVICE:
80                 app_state = APP_STATE_SERVICE;
81                 break;
82         default:
83                 app_state = APP_STATE_UNDEFINED;
84                 break;
85         }
86
87         return app_state;
88 }
89
90 static int app_context_foreach_app_context_cb(const aul_app_info *aul_app_context, void *cb_data)
91 {
92         foreach_context_s* foreach_context = cb_data;
93         app_context_h app_context;
94         app_state_e app_state;
95         bool is_sub_app = false;
96
97         if (foreach_context == NULL) {
98                 app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
99                 return 0;
100         }
101
102         if (foreach_context->iteration == true) {
103                 app_state = app_context_get_app_status(aul_app_context->status);
104
105                 if (aul_app_context->is_sub_app)
106                         is_sub_app = true;
107
108                 if (app_context_create(aul_app_context->appid,
109                                         aul_app_context->pid,
110                                         aul_app_context->pkgid,
111                                         app_state,
112                                         is_sub_app,
113                                         &app_context) == APP_MANAGER_ERROR_NONE) {
114                         foreach_context->iteration = foreach_context->callback(app_context, foreach_context->user_data);
115                         app_context_destroy(app_context);
116                 }
117         }
118
119         return 0;
120 }
121
122 int app_context_foreach_app_context(app_manager_app_context_cb callback, void *user_data)
123 {
124         foreach_context_s foreach_context = {
125                 .callback = callback,
126                 .user_data = user_data,
127                 .iteration = true
128         };
129
130         if (callback == NULL)
131                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
132
133         if (aul_app_get_running_app_info(app_context_foreach_app_context_cb, &foreach_context) != AUL_R_OK)
134                 return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, NULL);
135
136         return APP_MANAGER_ERROR_NONE;
137 }
138
139 static int app_context_foreach_running_app_context_cb(const aul_app_info *aul_app_context, void *cb_data)
140 {
141         foreach_context_s* foreach_context = cb_data;
142         app_context_h app_context;
143         app_state_e app_state;
144         bool is_sub_app = false;
145
146         if (foreach_context == NULL) {
147                 app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
148                 return 0;
149         }
150
151         if (foreach_context->iteration == true) {
152                 app_state = app_context_get_app_status(aul_app_context->status);
153
154                 if (aul_app_context->is_sub_app)
155                         is_sub_app = true;
156
157                 if (app_context_create(aul_app_context->appid,
158                                         aul_app_context->pid,
159                                         aul_app_context->pkgid,
160                                         app_state,
161                                         is_sub_app,
162                                         &app_context) == APP_MANAGER_ERROR_NONE) {
163                         foreach_context->iteration = foreach_context->callback(app_context, foreach_context->user_data);
164                         app_context_destroy(app_context);
165                 }
166         }
167
168         return 0;
169 }
170
171 int app_context_foreach_running_app_context(app_manager_app_context_cb callback, void *user_data)
172 {
173         int ret;
174         foreach_context_s foreach_context = {
175                 .callback = callback,
176                 .user_data = user_data,
177                 .iteration = true
178         };
179
180         if (callback == NULL)
181                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
182
183         ret = aul_app_get_all_running_app_info(app_context_foreach_running_app_context_cb, &foreach_context);
184         if (ret != AUL_R_OK) {
185                 if (ret == AUL_R_EILLACC)
186                         return app_manager_error(APP_MANAGER_ERROR_PERMISSION_DENIED, __FUNCTION__, NULL);
187                 else
188                         return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, NULL);
189         }
190
191         return APP_MANAGER_ERROR_NONE;
192 }
193
194 static int app_context_retrieve_app_context(const aul_app_info *aul_app_context, void *cb_data)
195 {
196         retrieval_context_s *retrieval_context = cb_data;
197         app_state_e app_state;
198
199         if (aul_app_context != NULL && retrieval_context != NULL && retrieval_context->matched == false) {
200                 if (!strcmp(aul_app_context->appid, retrieval_context->app_id)) {
201                         app_state = app_context_get_app_status(aul_app_context->status);
202
203                         retrieval_context->pid = aul_app_context->pid;
204                         retrieval_context->pkg_id = aul_app_context->pkgid;
205                         retrieval_context->app_state = app_state;
206                         if (aul_app_context->is_sub_app)
207                                 retrieval_context->is_sub_app = true;
208                         retrieval_context->matched = true;
209                 }
210         }
211
212         return 0;
213 }
214
215 int app_context_get_app_context(const char *app_id, app_context_h *app_context)
216 {
217         retrieval_context_s retrieval_context =  {
218                 .app_id = app_id,
219                 .pid = 0,
220                 .pkg_id = NULL,
221                 .app_state = APP_STATE_UNDEFINED,
222                 .is_sub_app = false,
223                 .matched = false
224         };
225
226         if (app_id == NULL || app_context == NULL)
227                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
228
229         if (aul_app_is_running(app_id) == 0)
230                 return app_manager_error(APP_MANAGER_ERROR_NO_SUCH_APP, __FUNCTION__, NULL);
231
232         aul_app_get_running_app_info(app_context_retrieve_app_context, &retrieval_context);
233
234         if (retrieval_context.matched == false)
235                 return app_manager_error(APP_MANAGER_ERROR_NO_SUCH_APP, __FUNCTION__, NULL);
236
237
238         return app_context_create(retrieval_context.app_id,
239                                         retrieval_context.pid,
240                                         retrieval_context.pkg_id,
241                                         retrieval_context.app_state,
242                                         retrieval_context.is_sub_app,
243                                          app_context);
244 }
245
246 static int app_context_create(const char *app_id, pid_t pid, char *pkg_id, app_state_e app_state, bool is_sub_app, app_context_h *app_context)
247 {
248         app_context_h app_context_created;
249
250         if (app_id == NULL || pid <= 0 || pkg_id == NULL || app_context == NULL)
251                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
252
253         app_context_created = calloc(1, sizeof(struct app_context_s));
254         if (app_context_created == NULL)
255                 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
256
257         app_context_created->app_id = strdup(app_id);
258         if (app_context_created->app_id == NULL) {
259                 free(app_context_created);
260                 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
261         }
262
263         app_context_created->pkg_id = strdup(pkg_id);
264         if (app_context_created->pkg_id == NULL) {
265                 free(app_context_created->app_id);
266                 free(app_context_created);
267                 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
268         }
269
270         app_context_created->pid = pid;
271         app_context_created->app_state = app_state;
272         app_context_created->is_sub_app = is_sub_app;
273
274         *app_context = app_context_created;
275
276         return APP_MANAGER_ERROR_NONE;
277 }
278
279 API int app_context_destroy(app_context_h app_context)
280 {
281         if (app_context == NULL)
282                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
283
284         free(app_context->app_id);
285         free(app_context->pkg_id);
286         free(app_context);
287
288         return APP_MANAGER_ERROR_NONE;
289 }
290
291 API int app_context_get_package(app_context_h app_context, char **package)
292 {
293         /* TODO: this function must be deprecated */
294         return app_context_get_app_id(app_context, package);
295 }
296
297
298 API int app_context_get_app_id(app_context_h app_context, char **app_id)
299 {
300         char *app_id_dup;
301
302         if (app_context == NULL || app_id == NULL)
303                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
304
305         app_id_dup = strdup(app_context->app_id);
306         if (app_id_dup == NULL)
307                 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
308
309         *app_id = app_id_dup;
310
311         return APP_MANAGER_ERROR_NONE;
312 }
313
314 API int app_context_get_pid(app_context_h app_context, pid_t *pid)
315 {
316         if (app_context == NULL || pid == NULL)
317                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
318
319         *pid = app_context->pid;
320
321         return APP_MANAGER_ERROR_NONE;
322 }
323
324 API int app_context_get_package_id(app_context_h app_context, char **pkg_id)
325 {
326         char *pkg_id_dup;
327
328         if (app_context == NULL || pkg_id == NULL)
329                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
330
331         pkg_id_dup = strdup(app_context->pkg_id);
332         if (pkg_id_dup == NULL)
333                 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
334
335         *pkg_id = pkg_id_dup;
336
337         return APP_MANAGER_ERROR_NONE;
338 }
339
340 API int app_context_get_app_state(app_context_h app_context, app_state_e *state)
341 {
342         if (app_context == NULL || state == NULL)
343                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
344
345         *state = app_context->app_state;
346
347         return APP_MANAGER_ERROR_NONE;
348 }
349
350 API int app_context_is_terminated(app_context_h app_context, bool *terminated)
351 {
352         if (app_context == NULL || terminated == NULL)
353                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
354
355         if (aul_app_is_running(app_context->app_id) == 1) {
356                 *terminated = false;
357         } else {
358                 char appid[APPID_MAX] = {0, };
359
360                 if (aul_app_get_appid_bypid(app_context->pid, appid, sizeof(appid)) == AUL_R_OK)
361                         *terminated = false;
362                 else
363                         *terminated = true;
364         }
365
366         return APP_MANAGER_ERROR_NONE;
367 }
368
369 API int app_context_is_equal(app_context_h lhs, app_context_h rhs, bool *equal)
370 {
371         if (lhs == NULL || rhs == NULL || equal == NULL)
372                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
373
374         if (!strcmp(lhs->app_id, rhs->app_id) && lhs->pid == rhs->pid)
375                 *equal = true;
376         else
377                 *equal = false;
378
379         return APP_MANAGER_ERROR_NONE;
380 }
381
382 API int app_context_is_sub_app(app_context_h app_context, bool *is_sub_app)
383 {
384         if (app_context == NULL || is_sub_app == NULL)
385                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
386
387         *is_sub_app = app_context->is_sub_app;
388
389         return APP_MANAGER_ERROR_NONE;
390 }
391
392 API int app_context_clone(app_context_h *clone, app_context_h app_context)
393 {
394         int retval;
395
396         if (clone == NULL || app_context == NULL)
397                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
398
399         retval = app_context_create(app_context->app_id,
400                                         app_context->pid,
401                                         app_context->pkg_id,
402                                         app_context->app_state,
403                                         app_context->is_sub_app,
404                                         clone);
405         if (retval != APP_MANAGER_ERROR_NONE)
406                 return app_manager_error(retval, __FUNCTION__, NULL);
407
408         return APP_MANAGER_ERROR_NONE;
409 }
410
411 typedef struct _event_cb_context_ {
412         GHashTable *pid_table;
413         app_manager_app_context_event_cb callback;
414         void *user_data;
415 } event_cb_context_s;
416
417 static pthread_mutex_t event_cb_context_mutex = PTHREAD_MUTEX_INITIALIZER;
418 static event_cb_context_s *event_cb_context = NULL;
419
420 static void app_context_lock_event_cb_context()
421 {
422         pthread_mutex_lock(&event_cb_context_mutex);
423 }
424
425 static void app_context_unlock_event_cb_context()
426 {
427         pthread_mutex_unlock(&event_cb_context_mutex);
428 }
429
430 static bool app_context_load_all_app_context_cb_locked(app_context_h app_context, void *user_data)
431 {
432         app_context_h app_context_cloned;
433
434         if (app_context_clone(&app_context_cloned, app_context) == APP_MANAGER_ERROR_NONE) {
435                 SECURE_LOGI("[%s] app_id(%s), pid(%d)", __FUNCTION__, app_context->app_id, app_context->pid);
436
437                 if (event_cb_context != NULL && event_cb_context->pid_table != NULL) {
438                         g_hash_table_insert(event_cb_context->pid_table, GINT_TO_POINTER(&(app_context_cloned->pid)), app_context_cloned);
439                 } else {
440                         app_context_destroy(app_context_cloned);
441                         app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "invalid callback context");
442                 }
443         }
444
445         return true;
446 }
447
448 static void app_context_pid_table_entry_destroyed_cb(void * data)
449 {
450         app_context_h app_context = data;
451
452         if (app_context != NULL)
453                 app_context_destroy(app_context);
454 }
455
456 static int app_context_get_pkgid_by_appid(const char *app_id, char **pkg_id)
457 {
458         pkgmgrinfo_appinfo_h appinfo;
459         char *pkg_id_dup;
460
461         if (app_id == NULL || pkg_id == NULL)
462                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
463
464         if (pkgmgrinfo_appinfo_get_usr_appinfo(app_id, getuid(), &appinfo) < 0)
465                 return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "fail to get appinfo");
466
467         if (pkgmgrinfo_appinfo_get_pkgid(appinfo, &pkg_id_dup) < 0) {
468                 pkgmgrinfo_appinfo_destroy_appinfo(appinfo);
469                 return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "fail to get pkgid");
470         }
471
472         *pkg_id = strdup(pkg_id_dup);
473
474         pkgmgrinfo_appinfo_destroy_appinfo(appinfo);
475         return APP_MANAGER_ERROR_NONE;
476 }
477
478 static int app_context_launched_event_cb(pid_t pid, const char *app_id, void *data)
479 {
480         app_context_h app_context = NULL;
481         char *pkg_id = NULL;
482
483         if (pid < 0 || app_id == NULL)
484                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
485
486         if (app_context_get_pkgid_by_appid(app_id, &pkg_id) < 0)
487                 return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "no such pkg_id");
488
489         app_context_lock_event_cb_context();
490
491         if (app_context_create(app_id, pid, pkg_id, APP_STATE_UNDEFINED, false, &app_context) == APP_MANAGER_ERROR_NONE) {
492                 if (event_cb_context != NULL && event_cb_context->pid_table != NULL) {
493                         g_hash_table_insert(event_cb_context->pid_table, GINT_TO_POINTER(&(app_context->pid)), app_context);
494                         event_cb_context->callback(app_context, APP_CONTEXT_EVENT_LAUNCHED, event_cb_context->user_data);
495                 } else {
496                         app_context_destroy(app_context);
497                         app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "invalid callback context");
498                 }
499         }
500
501         app_context_unlock_event_cb_context();
502
503         free(pkg_id);
504         return 0;
505 }
506
507 static int app_context_terminated_event_cb(pid_t pid, void *data)
508 {
509         app_context_h app_context;
510         int lookup_key = pid;
511
512         app_context_lock_event_cb_context();
513
514         if (event_cb_context != NULL && event_cb_context->pid_table != NULL) {
515                 app_context = g_hash_table_lookup(event_cb_context->pid_table, GINT_TO_POINTER(&lookup_key));
516
517                 if (app_context != NULL) {
518                         event_cb_context->callback(app_context, APP_CONTEXT_EVENT_TERMINATED, event_cb_context->user_data);
519                         g_hash_table_remove(event_cb_context->pid_table, GINT_TO_POINTER(&(app_context->pid)));
520                 }
521         } else {
522                 app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "invalid callback context");
523         }
524
525         app_context_unlock_event_cb_context();
526
527         return 0;
528 }
529
530 int app_context_set_event_cb(app_manager_app_context_event_cb callback, void *user_data)
531 {
532         if (callback == NULL)
533                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
534
535         app_context_lock_event_cb_context();
536
537         if (event_cb_context == NULL) {
538                 event_cb_context = calloc(1, sizeof(event_cb_context_s));
539
540                 if (event_cb_context == NULL) {
541                         app_context_unlock_event_cb_context();
542                         return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
543                 }
544
545                 event_cb_context->pid_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, app_context_pid_table_entry_destroyed_cb);
546                 if (event_cb_context->pid_table == NULL) {
547                         free(event_cb_context);
548                         event_cb_context = NULL;
549                         app_context_unlock_event_cb_context();
550                         return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "failed to initialize pid-table");
551                 }
552
553                 app_context_foreach_app_context(app_context_load_all_app_context_cb_locked, NULL);
554
555                 aul_listen_app_dead_signal(app_context_terminated_event_cb, NULL);
556                 aul_listen_app_launch_signal_v2(app_context_launched_event_cb, NULL);
557
558         }
559
560         event_cb_context->callback = callback;
561         event_cb_context->user_data = user_data;
562
563         app_context_unlock_event_cb_context();
564
565         return APP_MANAGER_ERROR_NONE;
566 }
567
568 void app_context_unset_event_cb(void)
569 {
570         app_context_lock_event_cb_context();
571
572         if (event_cb_context != NULL) {
573                 /* aul_listen_app_dead_signal(NULL, NULL); */
574                 /* aul_listen_app_launch_signal(NULL, NULL); */
575
576                 g_hash_table_destroy(event_cb_context->pid_table);
577                 free(event_cb_context);
578                 event_cb_context = NULL;
579         }
580
581         app_context_unlock_event_cb_context();
582 }