report-json-serializer: app and top serializers
[apps/native/ttsd-worker-task.git] / src / appinfo-provider.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 #include <glib.h>
18 #include <gio/gio.h>
19 #include <aul.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include "appinfo-provider.h"
23 #include "err-check.h"
24 #include "log.h"
25
26 #define AUL_APPSTATUS_OBJECT_PATH "/Org/Tizen/Aul/AppStatus"
27 #define AUL_APPSTATUS_INTERFACE_NAME "org.tizen.aul.AppStatus"
28 #define SIGNAL_AMD_LAUNCH "AppLaunch"
29 #define SIGNAL_AMD_TERMINATED "AppTerminated"
30
31 struct app_info_descriptor
32 {
33         int pid;
34         char *app_id;
35 };
36
37 static struct app_info_data
38 {
39         GMutex mutex;
40         GArray *app_data;
41         GDBusConnection *dbus_conn;
42 } app_info = {
43         .app_data = NULL,
44         .dbus_conn = NULL
45 };
46
47 struct app_info_iterator
48 {
49         GArray *data;
50         int position;
51 };
52
53 typedef void(*dbus_signal_cb)(GVariant *parameters);
54
55 static void add_app(int pid, const char *app_id);
56 static void remove_app_by_pid(int pid);
57 static GDBusConnection *dbus_create_connection();
58 static void dbus_register_signal(const char *path, const char *interface,
59                 const char *name, dbus_signal_cb callback);
60
61 static int running_apps_iter(const aul_app_info* info, void* data);
62 static void app_launched(GVariant *parameters);
63 static void app_terminated(GVariant *parameters);
64
65 bool app_info_iterator_next(app_info_iterator_t *iter)
66 {
67         ON_NULL_RETURN_VAL(iter, false);
68
69         if (iter->position >= iter->data->len - 1)
70                 return false;
71
72         iter->position++;
73         return true;
74 }
75
76 const char *app_info_iterator_get_app_id(app_info_iterator_t *iter)
77 {
78         ON_NULL_RETURN_VAL(iter, NULL);
79
80         struct app_info_descriptor elem = g_array_index(iter->data, struct app_info_descriptor, iter->position);
81         return elem.app_id;
82 }
83
84 int app_info_iterator_get_pid(app_info_iterator_t *iter)
85 {
86         ON_NULL_RETURN_VAL(iter, -1);
87
88         struct app_info_descriptor elem = g_array_index(iter->data, struct app_info_descriptor, iter->position);
89         return elem.pid;
90 }
91
92 void app_info_iterator_free(app_info_iterator_t *iter)
93 {
94         ON_NULL_RETURN(iter);
95
96         struct app_info_descriptor elem;
97         for (int i = 0; i < iter->data->len; i++)
98         {
99                 elem = g_array_index(app_info.app_data, struct app_info_descriptor, i);
100                 g_free(elem.app_id);
101         }
102
103         g_array_free(iter->data, TRUE);
104         g_free(iter);
105 }
106
107
108 app_info_iterator_t *app_info_provider_get_running_applications()
109 {
110         struct app_info_descriptor elem;
111         struct app_info_iterator *iter = (struct app_info_iterator *)g_malloc(sizeof(struct app_info_iterator));
112         iter->position = 0;
113         iter->data = g_array_new(FALSE, TRUE, sizeof(struct app_info_descriptor));
114
115         g_mutex_lock(&app_info.mutex);
116
117         for (int i = 0; i < app_info.app_data->len; i++)
118         {
119                 elem = g_array_index(app_info.app_data, struct app_info_descriptor, i);
120                 struct app_info_descriptor cpy;
121                 cpy.pid = elem.pid;
122                 if (elem.app_id)
123                         cpy.app_id = strdup(elem.app_id);
124
125                 g_array_append_val(iter->data, cpy);
126         }
127
128         g_mutex_unlock(&app_info.mutex);
129
130         if (iter->data->len == 0)
131         {
132                 g_array_free(iter->data, TRUE);
133                 g_free(iter);
134                 return NULL;
135         }
136
137         return iter;
138 }
139
140 int app_info_provider_find_main_pid(const char *app_id)
141 {
142         ON_NULL_RETURN_VAL(app_id, -1);
143
144         struct app_info_descriptor elem;
145
146         g_mutex_lock(&app_info.mutex);
147
148         for (int i = 0; i < app_info.app_data->len; i++)
149         {
150                 elem = g_array_index(app_info.app_data, struct app_info_descriptor, i);
151
152                 if (elem.app_id && strcmp(elem.app_id, app_id) == 0)
153                 {
154                         g_mutex_unlock(&app_info.mutex);
155                         return elem.pid;
156                 }
157         }
158
159         g_mutex_unlock(&app_info.mutex);
160         return -1;
161 }
162
163 char *app_info_provider_find_app_id(int pid)
164 {
165         struct app_info_descriptor elem;
166
167         g_mutex_lock(&app_info.mutex);
168
169         for (int i = 0; i < app_info.app_data->len; i++)
170         {
171                 elem = g_array_index(app_info.app_data, struct app_info_descriptor, i);
172
173                 if (elem.pid == pid && elem.app_id)
174                 {
175                         char *id = strdup(elem.app_id);
176                         g_mutex_unlock(&app_info.mutex);
177                         return id;
178                 }
179         }
180
181         g_mutex_unlock(&app_info.mutex);
182         return NULL;
183 }
184
185 int app_provider_init()
186 {
187         g_mutex_init(&app_info.mutex);
188         app_info.app_data = g_array_new(FALSE, TRUE, sizeof(struct app_info_descriptor));
189
190         app_info.dbus_conn = dbus_create_connection();
191         if (!(app_info.dbus_conn))
192                 return -1;
193
194         aul_app_get_all_running_app_info(running_apps_iter, NULL);
195
196         dbus_register_signal(AUL_APPSTATUS_OBJECT_PATH, AUL_APPSTATUS_INTERFACE_NAME, SIGNAL_AMD_LAUNCH, app_launched);
197         dbus_register_signal(AUL_APPSTATUS_OBJECT_PATH, AUL_APPSTATUS_INTERFACE_NAME, SIGNAL_AMD_TERMINATED, app_terminated);
198
199         return 0;
200 }
201
202 void app_provider_shutdown()
203 {
204         g_array_free(app_info.app_data, TRUE);
205         g_object_unref(app_info.dbus_conn);
206         g_mutex_clear(&app_info.mutex);
207 }
208
209 static int running_apps_iter(const aul_app_info* info, void* data)
210 {
211         add_app(info->pid, info->appid);
212         return 0;
213 }
214
215 static void add_app(int pid, const char *app_id)
216 {
217         ON_NULL_RETURN(app_id);
218
219         struct app_info_descriptor descr;
220
221         descr.pid = pid;
222
223         int len = strlen(app_id) + 1;
224         char *_app_id = (char *)g_malloc(len * sizeof(char));
225         snprintf(_app_id, len, "%s", app_id);
226         descr.app_id = _app_id;
227
228         g_mutex_lock(&app_info.mutex);
229
230         g_array_append_val(app_info.app_data, descr);
231
232         g_mutex_unlock(&app_info.mutex);
233 }
234
235 static void remove_app_by_pid(int pid)
236 {
237         g_mutex_lock(&app_info.mutex);
238         struct app_info_descriptor elem;
239
240         for (int i = 0; i < app_info.app_data->len; i++)
241         {
242                 elem = g_array_index(app_info.app_data, struct app_info_descriptor, i);
243                 if (elem.pid == pid)
244                 {
245                         g_free(elem.app_id);
246                         g_array_remove_index(app_info.app_data, i);
247                         break;
248                 }
249         }
250         g_mutex_unlock(&app_info.mutex);
251 }
252
253 static GDBusConnection *dbus_create_connection()
254 {
255         GError *err = NULL;
256         GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
257         if(err)
258         {
259                 ERR("Failed to create GDbusConnection ", err->message);
260         g_error_free (err);
261         return NULL;
262         }
263
264         return conn;
265 }
266
267 static void d_bus_signal_handler(GDBusConnection *connection,
268                 const gchar *sender, const gchar *object_path,
269                 const gchar *interface_name, const gchar *signal_name,
270                 GVariant *parameters, gpointer user_data)
271 {
272         dbus_signal_cb cb = (dbus_signal_cb)user_data;
273         if (!cb)
274                 return;
275
276         cb(parameters);
277 }
278
279 static void dbus_register_signal(const char *path, const char *interface,
280                 const char *name, dbus_signal_cb callback)
281 {
282         g_dbus_connection_signal_subscribe(app_info.dbus_conn,
283                 NULL, interface, name, path, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
284                         d_bus_signal_handler, callback, NULL);
285 }
286
287 static void app_launched(GVariant *parameters)
288 {
289         pid_t pid = 0;
290         char *app_id = NULL;
291         char *pkg_id = NULL;
292         char *pkg_type = NULL;
293
294         g_variant_get(parameters, "(i&s&s&s)", &pid, &app_id, &pkg_id, &pkg_type);
295         if (pid == 0 || !app_id || !pkg_id || !pkg_type) {
296                 ERR("There is no message");
297                 return;
298         }
299
300         add_app(pid, app_id);
301 }
302
303 static void app_terminated(GVariant *parameters)
304 {
305         pid_t pid = 0;
306
307         g_variant_get(parameters, "(i)", &pid);
308         if (pid == 0) {
309                 ERR("There is no message");
310                 return;
311         }
312
313         remove_app_by_pid(pid);
314 }