Upload Tizen2.0 source
[framework/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
29 #include <app_context.h>
30 #include <app_manager.h>
31 #include <app_manager_private.h>
32
33 #ifdef LOG_TAG
34 #undef LOG_TAG
35 #endif
36
37 #define LOG_TAG "TIZEN_N_APP_MANAGER"
38
39 #define APPID_MAX 128
40
41 static int app_context_create(const char *app_id, pid_t pid, app_context_h *app_context);
42
43 static int app_context_get_app_context_by_pid(pid_t pid, app_context_h *app_context);
44
45 struct app_context_s {
46         char *app_id;
47         pid_t pid;
48 };
49
50 typedef struct _foreach_context_ {
51         app_manager_app_context_cb callback;
52         void *user_data;
53         bool iteration;
54 } foreach_context_s;
55
56 typedef struct _retrieval_context_{
57         const char *app_id;
58         pid_t pid;
59         bool matched;
60 } retrieval_context_s;
61
62 static int app_context_foreach_app_context_cb(const aul_app_info *aul_app_context, void *cb_data)
63 {
64         foreach_context_s* foreach_context = cb_data;
65
66         if (foreach_context == NULL)
67         {
68                 app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
69                 return 0;
70         }
71
72         if (foreach_context->iteration == true)
73         {
74                 app_context_h app_context = NULL;
75
76                 if (app_context_create(aul_app_context->pkg_name, aul_app_context->pid, &app_context) == APP_MANAGER_ERROR_NONE)
77                 {
78                         foreach_context->iteration = foreach_context->callback(app_context, foreach_context->user_data);
79                         app_context_destroy(app_context);
80                 }
81         }
82
83         return 0;
84 }
85
86
87 int app_context_foreach_app_context(app_manager_app_context_cb callback, void *user_data)
88 {
89         foreach_context_s foreach_context = {
90                 .callback = callback,
91                 .user_data = user_data,
92                 .iteration = true
93         };
94
95         if (callback == NULL)
96         {
97                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
98         }
99
100         aul_app_get_running_app_info(app_context_foreach_app_context_cb, &foreach_context);
101
102         return APP_MANAGER_ERROR_NONE;
103 }
104
105
106 static int app_context_retrieve_app_context(const aul_app_info *aul_app_context, void *cb_data)
107 {
108         retrieval_context_s *retrieval_context = cb_data;
109
110         if (aul_app_context != NULL && retrieval_context != NULL && retrieval_context->matched == false)
111         {
112                 if (!strcmp(aul_app_context->pkg_name, retrieval_context->app_id))
113                 {
114                         retrieval_context->pid = aul_app_context->pid;
115                         retrieval_context->matched = true;
116                 }
117         }
118
119         return 0;
120 }
121
122 int app_context_get_app_context(const char *app_id, app_context_h *app_context)
123 {
124         retrieval_context_s retrieval_context =  {
125                 .app_id = app_id,
126                 .pid = 0,
127                 .matched = false
128         };
129
130         if (app_id == NULL || app_context == NULL)
131         {
132                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
133         }
134
135         if (aul_app_is_running(app_id) == 0)
136         {
137                 return app_manager_error(APP_MANAGER_ERROR_NO_SUCH_APP, __FUNCTION__, NULL);
138         }
139
140         aul_app_get_running_app_info(app_context_retrieve_app_context, &retrieval_context);
141
142         if (retrieval_context.matched == false)
143         {
144                 return app_manager_error(APP_MANAGER_ERROR_NO_SUCH_APP, __FUNCTION__, NULL);
145         }
146
147         return app_context_create(retrieval_context.app_id, retrieval_context.pid, app_context);
148 }
149
150 static int app_context_get_app_context_by_pid(pid_t pid, app_context_h *app_context)
151 {
152         int retval;
153         char appid[APPID_MAX] = {0, };
154
155         if (pid < 0 || app_context == NULL)
156         {
157                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
158         }
159
160         if (aul_app_get_pkgname_bypid(pid, appid, sizeof(appid)) != AUL_R_OK)
161         {
162                 return app_manager_error(APP_MANAGER_ERROR_NO_SUCH_APP, __FUNCTION__, NULL);
163         }
164
165         retval = app_context_get_app_context(appid, app_context);
166
167         if (retval != APP_MANAGER_ERROR_NONE)
168         {
169                 return app_manager_error(retval, __FUNCTION__, NULL);
170         }
171
172         return APP_MANAGER_ERROR_NONE;
173 }
174
175 static int app_context_create(const char *app_id, pid_t pid, app_context_h *app_context)
176 {
177         app_context_h app_context_created;
178
179         if (app_id == NULL || pid <= 0 || app_context == NULL)
180         {
181                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
182         }
183
184         app_context_created = calloc(1, sizeof(struct app_context_s));
185
186         if (app_context_created == NULL)
187         {
188                 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
189         }
190
191         app_context_created->app_id = strdup(app_id);
192
193         if (app_context_created->app_id == NULL)
194         {
195                 free(app_context_created);
196                 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
197         }
198
199         app_context_created->pid = pid;
200
201         *app_context = app_context_created;
202
203         return APP_MANAGER_ERROR_NONE;
204 }
205
206 int app_context_destroy(app_context_h app_context)
207 {
208         if (app_context == NULL)
209         {
210                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
211         }
212
213         free(app_context->app_id);
214         free(app_context);
215
216         return APP_MANAGER_ERROR_NONE;
217 }
218
219 int app_context_get_package(app_context_h app_context, char **package)
220 {
221         // TODO: this function must be deprecated
222         return app_context_get_app_id(app_context, package);
223 }
224
225
226 int app_context_get_app_id(app_context_h app_context, char **app_id)
227 {
228         char *app_id_dup;
229
230         if (app_context == NULL || app_id == NULL)
231         {
232                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
233         }
234
235         app_id_dup = strdup(app_context->app_id);
236
237         if (app_id_dup == NULL)
238         {
239                 return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
240         }
241
242         *app_id = app_id_dup;
243
244         return APP_MANAGER_ERROR_NONE;
245 }
246
247
248 int app_context_get_pid(app_context_h app_context, pid_t *pid)
249 {
250         if (app_context == NULL || pid == NULL)
251         {
252                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
253         }
254
255         *pid = app_context->pid;
256
257         return APP_MANAGER_ERROR_NONE;
258 }
259
260 int app_context_is_terminated(app_context_h app_context, bool *terminated)
261 {
262         if (app_context == NULL || terminated == NULL)
263         {
264                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
265         }
266
267         if (aul_app_is_running(app_context->app_id) == 1)
268         {
269                 *terminated = false;
270         }
271         else
272         {
273                 char appid[APPID_MAX] = {0, };
274
275                 if (aul_app_get_pkgname_bypid(app_context->pid, appid, sizeof(appid)) == AUL_R_OK)
276                 {
277                         *terminated = false;
278                 }
279                 else
280                 {
281                         *terminated = true;
282                 }
283         }
284
285         return APP_MANAGER_ERROR_NONE;
286 }
287
288 int app_context_is_equal(app_context_h lhs, app_context_h rhs, bool *equal)
289 {
290         if (lhs == NULL || rhs == NULL || equal == NULL)
291         {
292                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
293         }
294
295         if (!strcmp(lhs->app_id, rhs->app_id) && lhs->pid == rhs->pid)
296         {
297                 *equal = true;
298         }
299         else
300         {
301                 *equal = false;
302         }
303
304         return APP_MANAGER_ERROR_NONE;
305 }
306
307 int app_context_clone(app_context_h *clone, app_context_h app_context)
308 {
309         int retval;
310
311         if (clone == NULL || app_context == NULL)
312         {
313                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
314         }
315
316         retval = app_context_create(app_context->app_id, app_context->pid, clone);
317
318         if (retval != APP_MANAGER_ERROR_NONE)
319         {
320                 return app_manager_error(retval, __FUNCTION__, NULL);
321         }
322
323         return APP_MANAGER_ERROR_NONE;
324 }
325
326 typedef struct _event_cb_context_ {
327         GHashTable *pid_table;
328         app_manager_app_context_event_cb callback;
329         void *user_data;
330 } event_cb_context_s;
331
332 static pthread_mutex_t event_cb_context_mutex = PTHREAD_MUTEX_INITIALIZER;
333 static event_cb_context_s *event_cb_context = NULL;
334
335 static void app_context_lock_event_cb_context()
336 {
337         pthread_mutex_lock(&event_cb_context_mutex);
338 }
339
340 static void app_context_unlock_event_cb_context()
341 {
342         pthread_mutex_unlock(&event_cb_context_mutex);
343 }
344
345 static bool app_context_load_all_app_context_cb_locked(app_context_h app_context, void *user_data)
346 {
347         app_context_h app_context_cloned;
348
349         if (app_context_clone(&app_context_cloned, app_context) == APP_MANAGER_ERROR_NONE)
350         {
351                 LOGI("[%s] app_id(%s), pid(%d)", __FUNCTION__, app_context->app_id, app_context->pid);
352
353                 if (event_cb_context != NULL && event_cb_context->pid_table != NULL)
354                 {
355                         g_hash_table_insert(event_cb_context->pid_table, GINT_TO_POINTER(&(app_context_cloned->pid)), app_context_cloned);
356                 }
357                 else
358                 {
359                         app_context_destroy(app_context_cloned);
360                         app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "invalid callback context");
361                 }
362         }
363
364         return true;
365 }
366
367 static void app_context_pid_table_entry_destroyed_cb(void * data)
368 {
369         app_context_h app_context = data;
370
371         if (app_context != NULL)
372         {
373                 char *app_id;
374                 int pid;
375                 app_context_get_package(app_context, &app_id);
376                 app_context_get_pid(app_context, &pid);
377                 LOGI("[%s] app_id(%s), pid(%d)", __FUNCTION__, app_context->app_id, app_context->pid);
378                 free(app_id);
379
380                 app_context_destroy(app_context);
381         }
382 }
383
384 static int app_context_launched_event_cb(pid_t pid, void *data)
385 {
386         app_context_h app_context;
387
388         app_context_lock_event_cb_context();
389
390         if (app_context_get_app_context_by_pid(pid, &app_context) == APP_MANAGER_ERROR_NONE)
391         {
392                 if (event_cb_context != NULL && event_cb_context->pid_table != NULL)
393                 {
394                         g_hash_table_insert(event_cb_context->pid_table, GINT_TO_POINTER(&(app_context->pid)), app_context);
395                         event_cb_context->callback(app_context, APP_CONTEXT_EVENT_LAUNCHED, event_cb_context->user_data);
396                 }
397                 else
398                 {
399                         app_context_destroy(app_context);
400                         app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "invalid callback context");
401                 }
402         }
403
404         app_context_unlock_event_cb_context();
405
406         return 0;
407 }
408
409 static int app_context_terminated_event_cb(pid_t pid, void *data)
410 {
411         app_context_h app_context;
412         int lookup_key = pid;
413
414         app_context_lock_event_cb_context();
415
416         if (event_cb_context != NULL && event_cb_context->pid_table != NULL)
417         {
418                 app_context = g_hash_table_lookup(event_cb_context->pid_table, GINT_TO_POINTER(&lookup_key));
419
420                 if (app_context != NULL)
421                 {
422                         event_cb_context->callback(app_context, APP_CONTEXT_EVENT_TERMINATED, event_cb_context->user_data);
423                         g_hash_table_remove(event_cb_context->pid_table, GINT_TO_POINTER(&(app_context->pid)));
424                 }
425         }
426         else
427         {
428                 app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "invalid callback context");
429         }
430
431         app_context_unlock_event_cb_context();
432
433         return 0;
434 }
435
436 int app_context_set_event_cb(app_manager_app_context_event_cb callback, void *user_data)
437 {
438         if (callback == NULL)
439         {
440                 return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
441         }
442
443         app_context_lock_event_cb_context();
444
445         if (event_cb_context == NULL)
446         {
447                 event_cb_context = calloc(1, sizeof(event_cb_context_s));
448
449                 if (event_cb_context == NULL)
450                 {
451                         return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
452                 }
453
454                 event_cb_context->pid_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, app_context_pid_table_entry_destroyed_cb);
455         
456                 if (event_cb_context->pid_table == NULL)
457                 {
458                         return app_manager_error(APP_MANAGER_ERROR_IO_ERROR, __FUNCTION__, "failed to initialize pid-table");
459                 }
460
461                 app_context_foreach_app_context(app_context_load_all_app_context_cb_locked, NULL);
462
463                 aul_listen_app_dead_signal(app_context_terminated_event_cb, NULL);
464                 aul_listen_app_launch_signal(app_context_launched_event_cb, NULL);
465
466         }
467         
468         event_cb_context->callback = callback;
469         event_cb_context->user_data = user_data;
470
471         app_context_unlock_event_cb_context();
472
473         return APP_MANAGER_ERROR_NONE;
474 }
475
476 void app_context_unset_event_cb(void)
477 {
478         app_context_lock_event_cb_context();
479
480         if (event_cb_context != NULL)
481         {
482                 //aul_listen_app_dead_signal(NULL, NULL);
483                 //aul_listen_app_launch_signal(NULL, NULL);
484
485                 g_hash_table_destroy(event_cb_context->pid_table);
486                 free(event_cb_context);
487                 event_cb_context = NULL;
488         }
489
490         app_context_unlock_event_cb_context();
491 }
492