1 /* vi:set et ai sw=2 sts=2 ts=2: */
3 * Copyright (c) 2012 GENIVI.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 #include <glib-object.h>
17 #include <boot-manager/boot-manager-service.h>
18 #include <boot-manager/luc-starter.h>
19 #include <luc-handler/luc-handler-dbus.h>
23 /* property identifiers */
33 static void luc_starter_constructed (GObject *object);
34 static void luc_starter_finalize (GObject *object);
35 static void luc_starter_get_property (GObject *object,
39 static void luc_starter_set_property (GObject *object,
43 static gint luc_starter_compare_luc_types (gconstpointer a,
46 static void luc_starter_start_next_group (LUCStarter *starter);
47 static void luc_starter_start_app (const gchar *app,
49 static void luc_starter_start_app_finish (BootManagerService *service,
57 struct _LUCStarterClass
59 GObjectClass __parent__;
66 BootManagerService *boot_manager;
67 LUCHandler *luc_handler;
69 gchar **prioritised_types;
72 GHashTable *start_groups;
77 G_DEFINE_TYPE (LUCStarter, luc_starter, G_TYPE_OBJECT);
82 luc_starter_class_init (LUCStarterClass *klass)
84 GObjectClass *gobject_class;
86 gobject_class = G_OBJECT_CLASS (klass);
87 gobject_class->constructed = luc_starter_constructed;
88 gobject_class->finalize = luc_starter_finalize;
89 gobject_class->get_property = luc_starter_get_property;
90 gobject_class->set_property = luc_starter_set_property;
92 g_object_class_install_property (gobject_class,
94 g_param_spec_object ("boot-manager",
97 BOOT_MANAGER_TYPE_SERVICE,
99 G_PARAM_CONSTRUCT_ONLY |
100 G_PARAM_STATIC_STRINGS));
102 g_object_class_install_property (gobject_class,
104 g_param_spec_object ("luc-handler",
109 G_PARAM_CONSTRUCT_ONLY |
110 G_PARAM_STATIC_STRINGS));
116 luc_starter_init (LUCStarter *starter)
123 luc_starter_constructed (GObject *object)
125 LUCStarter *starter = LUC_STARTER (object);
127 /* parse the prioritised LUC types defined at build-time */
128 starter->prioritised_types = g_strsplit (PRIORITISED_LUC_TYPES, ",", -1);
134 luc_starter_finalize (GObject *object)
136 LUCStarter *starter = LUC_STARTER (object);
138 /* free the prioritised types array */
139 g_strfreev (starter->prioritised_types);
141 /* release the boot manager */
142 g_object_unref (starter->boot_manager);
144 /* release the LUC handler */
145 g_object_unref (starter->luc_handler);
147 (*G_OBJECT_CLASS (luc_starter_parent_class)->finalize) (object);
153 luc_starter_get_property (GObject *object,
158 LUCStarter *starter = LUC_STARTER (object);
162 case PROP_BOOT_MANAGER:
163 g_value_set_object (value, starter->boot_manager);
165 case PROP_LUC_HANDLER:
166 g_value_set_object (value, starter->luc_handler);
169 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
177 luc_starter_set_property (GObject *object,
182 LUCStarter *starter = LUC_STARTER (object);
186 case PROP_BOOT_MANAGER:
187 starter->boot_manager = g_value_dup_object (value);
189 case PROP_LUC_HANDLER:
190 starter->luc_handler = g_value_dup_object (value);
193 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
201 luc_starter_compare_luc_types (gconstpointer a,
205 LUCStarter *starter = LUC_STARTER (user_data);
209 gint pos_a = G_MAXINT;
210 gint pos_b = G_MAXINT;
212 /* try to find the first type in the prioritised types list */
213 for (n = 0; pos_a < 0 && starter->prioritised_types[n] != NULL; n++)
214 if (g_strcmp0 (starter->prioritised_types[n], type_a) == 0)
217 /* try to find the second type in the prioritised types list */
218 for (n = 0; pos_b < 0 && starter->prioritised_types[n] != NULL; n++)
219 if (g_strcmp0 (starter->prioritised_types[n], type_b) == 0)
222 /* this statement has the following effect when sorting:
223 * - a and b are prioritised -> prioritization order is preserved
224 * - a is prioritised, b isn't -> negative return value, a comes first
225 * - b is prioritised, a isn't -> positive return value, b comes first
226 * - neither a nor b prioritised -> return value is 0, arbitrary order
228 return pos_a - pos_b;
234 luc_starter_start_next_group (LUCStarter *starter)
236 const gchar *group_name;
239 g_return_if_fail (IS_LUC_STARTER (starter));
240 g_return_if_fail (starter->start_order != NULL);
242 group_name = starter->start_order->data;
244 g_debug ("start group '%s'", group_name);
246 /* look up the group with this name */
247 group = g_hash_table_lookup (starter->start_groups, group_name);
250 /* launch all the applications in the group asynchronously */
251 g_ptr_array_foreach (group, (GFunc) luc_starter_start_app, starter);
258 luc_starter_start_app (const gchar *app,
261 g_return_if_fail (app != NULL && *app != '\0');
262 g_return_if_fail (IS_LUC_STARTER (starter));
264 g_debug ("start app '%s'", app);
266 boot_manager_service_start (starter->boot_manager, app, NULL,
267 luc_starter_start_app_finish,
274 luc_starter_start_app_finish (BootManagerService *service,
280 const gchar *group_name;
281 LUCStarter *starter = LUC_STARTER (user_data);
283 gboolean app_found = FALSE;
286 g_return_if_fail (BOOT_MANAGER_IS_SERVICE (service));
287 g_return_if_fail (unit != NULL && *unit != '\0');
288 g_return_if_fail (IS_LUC_STARTER (user_data));
289 g_return_if_fail (starter->start_order != NULL);
291 g_debug ("start app '%s' finish", unit);
293 /* get the current start group */
294 group_name = starter->start_order->data;
296 /* look up the apps for this group */
297 group = g_hash_table_lookup (starter->start_groups, group_name);
300 /* try to find the current app in the group */
301 for (n = 0; !app_found && n < group->len; n++)
303 if (g_strcmp0 (unit, g_ptr_array_index (group, n)) == 0)
307 /* remove the app from the group */
309 g_ptr_array_remove_index (group, n-1);
311 /* check if this was the last app in the group to be started */
314 g_debug ("start group %s finish", group_name);
316 /* remove the group from the groups and the order */
317 g_hash_table_remove (starter->start_groups, group_name);
318 starter->start_order = g_list_delete_link (starter->start_order,
319 starter->start_order);
321 /* start the next group if there are any left */
322 if (starter->start_order != NULL)
323 luc_starter_start_next_group (starter);
331 luc_starter_new (BootManagerService *boot_manager,
332 LUCHandler *luc_handler)
334 g_return_val_if_fail (BOOT_MANAGER_IS_SERVICE (boot_manager), NULL);
335 g_return_val_if_fail (IS_LUC_HANDLER (luc_handler), NULL);
337 return g_object_new (TYPE_LUC_STARTER,
338 "boot-manager", boot_manager,
339 "luc-handler", luc_handler,
346 luc_starter_start_groups (LUCStarter *starter)
356 g_debug ("prioritised types:");
357 for (n = 0; starter->prioritised_types[n] != NULL; n++)
358 g_debug (" %s", starter->prioritised_types[n]);
360 /* clear the start order */
361 if (starter->start_order != NULL)
363 g_list_free (starter->start_order);
364 starter->start_order = NULL;
367 /* clear the start groups */
368 if (starter->start_groups != NULL)
370 g_hash_table_remove_all (starter->start_groups);
374 starter->start_groups =
375 g_hash_table_new_full (g_str_hash, g_str_equal,
376 g_free, (GDestroyNotify) g_ptr_array_free);
379 /* get the current last user context */
380 context = luc_handler_get_last_user_context (starter->luc_handler);
381 type = g_variant_print (context, TRUE);
382 g_debug ("context: %s", type);
384 /* create groups for all types in the LUC */
385 g_variant_iter_init (&iter, context);
386 while (g_variant_iter_loop (&iter, "{s^as}", &type, &apps))
388 group = g_ptr_array_new_with_free_func (g_free);
390 for (n = 0; apps != NULL && apps[n] != NULL; n++)
392 g_debug (" group %s app %s", type, apps[n]);
393 g_ptr_array_add (group, g_strdup (apps[n]));
396 g_hash_table_insert (starter->start_groups, g_strdup (type), group);
399 /* generate the start order by sorting the LUC types according to
400 * the prioritised types */
401 starter->start_order = g_hash_table_get_keys (starter->start_groups);
402 starter->start_order = g_list_sort_with_data (starter->start_order,
403 luc_starter_compare_luc_types,
406 g_debug ("start groups (ordered):");
407 for (lp = starter->start_order; lp != NULL; lp = lp->next)
408 g_debug (" %s", (gchar *)lp->data);
410 if (starter->start_order != NULL)
411 luc_starter_start_next_group (starter);