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