70a0a20ff20050a0632c0f00d6d3b0c8a9d9aba6
[profile/ivi/node-startup-controller.git] / boot-manager / la-handler-service.c
1 /* vi:set et ai sw=2 sts=2 ts=2: */
2 /* -
3  * Copyright (c) 2012 GENIVI.
4  *
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/.
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #include <glib-object.h>
15 #include <gio/gio.h>
16
17 #include <dlt/dlt.h>
18
19 #include <common/nsm-consumer-dbus.h>
20 #include <common/shutdown-consumer-dbus.h>
21
22 #include <boot-manager/job-manager.h>
23 #include <boot-manager/la-handler-dbus.h>
24 #include <boot-manager/la-handler-service.h>
25
26
27
28 DLT_IMPORT_CONTEXT (la_handler_context);
29
30
31   
32 /* property identifiers */
33 enum
34 {
35   PROP_0,
36   PROP_CONNECTION,
37   PROP_JOB_MANAGER,
38 };
39
40
41
42 typedef struct _LAHandlerServiceConsumerBundle LAHandlerServiceConsumerBundle;
43 typedef struct _LAHandlerServiceShutdownConsumer LAHandlerServiceShutdownConsumer;
44
45
46
47 static void     la_handler_service_constructed                              (GObject               *object);
48 static void     la_handler_service_finalize                                 (GObject               *object);
49 static void     la_handler_service_get_property                             (GObject               *object,
50                                                                              guint                  prop_id,
51                                                                              GValue                *value,
52                                                                              GParamSpec            *pspec);
53 static void     la_handler_service_set_property                             (GObject               *object,
54                                                                              guint                  prop_id,
55                                                                              const GValue          *value,
56                                                                              GParamSpec            *pspec);
57 static gboolean la_handler_service_handle_register                          (LAHandler             *interface,
58                                                                              GDBusMethodInvocation *invocation,
59                                                                              const gchar           *unit,
60                                                                              const gchar           *mode,
61                                                                              guint                  timeout,
62                                                                              LAHandlerService      *service);
63 static void     la_handler_service_handle_register_finish                   (NSMConsumer           *nsm_consumer,
64                                                                              GAsyncResult          *res,
65                                                                              GDBusMethodInvocation *invocation);
66 static gboolean la_handler_service_handle_deregister                        (LAHandler             *interface,
67                                                                              GDBusMethodInvocation *invocation,
68                                                                              const gchar           *unit,
69                                                                              LAHandlerService      *service);
70 static void     la_handler_service_handle_consumer_lifecycle_request        (ShutdownConsumer      *interface,
71                                                                              GDBusMethodInvocation *invocation,
72                                                                              guint                  request,
73                                                                              guint                  request_id,
74                                                                              LAHandlerService      *service);
75 static void     la_handler_service_handle_consumer_lifecycle_request_finish (JobManager            *manager,
76                                                                              const gchar           *unit,
77                                                                              const gchar           *result,
78                                                                              GError                *error,
79                                                                              gpointer               user_data);
80
81 struct _LAHandlerServiceClass
82 {
83   GObjectClass __parent__;
84 };
85
86 struct _LAHandlerService
87 {
88   GObject          __parent__;
89
90   GDBusConnection *connection;
91   LAHandler       *interface;
92   JobManager      *job_manager;
93
94   /* Associations of shutdown consumers and their units */
95   GHashTable      *units_to_consumers;
96   GHashTable      *consumers_to_units;
97
98   const gchar     *prefix;
99   guint            index;
100   guint            bus_name_id;
101
102   /* connection to the NSM consumer interface */
103   NSMConsumer     *nsm_consumer;
104 };
105
106
107
108 G_DEFINE_TYPE (LAHandlerService, la_handler_service, G_TYPE_OBJECT);
109
110
111
112 static void
113 la_handler_service_class_init (LAHandlerServiceClass *klass)
114 {
115   GObjectClass *gobject_class;
116
117   gobject_class = G_OBJECT_CLASS (klass);
118   gobject_class->constructed = la_handler_service_constructed;
119   gobject_class->finalize = la_handler_service_finalize;
120   gobject_class->get_property = la_handler_service_get_property;
121   gobject_class->set_property = la_handler_service_set_property;
122
123   g_object_class_install_property (gobject_class,
124                                    PROP_CONNECTION,
125                                    g_param_spec_object ("connection",
126                                                         "connection",
127                                                         "connection",
128                                                         G_TYPE_DBUS_CONNECTION,
129                                                         G_PARAM_READWRITE |
130                                                         G_PARAM_CONSTRUCT_ONLY |
131                                                         G_PARAM_STATIC_STRINGS));
132   g_object_class_install_property (gobject_class,
133                                    PROP_JOB_MANAGER,
134                                    g_param_spec_object ("job-manager",
135                                                         "Job Manager",
136                                                         "The internal handler of Start()"
137                                                         " and Stop() jobs",
138                                                         TYPE_JOB_MANAGER,
139                                                         G_PARAM_READWRITE |
140                                                         G_PARAM_CONSTRUCT_ONLY |
141                                                         G_PARAM_STATIC_STRINGS));
142 }
143
144
145
146 static void
147 la_handler_service_constructed (GObject *object)
148 {
149   LAHandlerService *service = LA_HANDLER_SERVICE (object);
150   GError           *error = NULL;
151   gchar            *log_text;
152
153   /* connect to the node state manager */
154   service->nsm_consumer =
155     nsm_consumer_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,
156                                          "com.contiautomotive.NodeStateManager",
157                                          "/com/contiautomotive/NodeStateManager/Consumer",
158                                           NULL, &error);
159   if (error != NULL)
160     {
161       log_text = g_strdup_printf ("Error occurred connecting to NSM Consumer: %s",
162                                   error->message);
163       DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
164       g_free (log_text);
165       g_error_free (error);
166     }
167 }
168
169
170
171 static void
172 la_handler_service_init (LAHandlerService *service)
173 {
174   service->interface = la_handler_skeleton_new ();
175
176   /* the number that follows the prefix in the shutdown consumer's object path,
177    * making every shutdown consumer unique */
178   service->index = 1;
179
180   /* the string that precedes the index in the shutdown consumer's object path */
181   service->prefix = "/org/genivi/BootManager1/ShutdownConsumer";
182
183   /* initialize the association of shutdown consumers to units */
184   service->units_to_consumers =
185     g_hash_table_new_full (g_str_hash, g_str_equal,
186                            (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref);
187   service->consumers_to_units =
188     g_hash_table_new_full (g_direct_hash, g_direct_equal, 
189                            (GDestroyNotify) g_object_unref, (GDestroyNotify) g_free);
190
191   /* implement the Register() handler */
192   g_signal_connect (service->interface, "handle-register",
193                     G_CALLBACK (la_handler_service_handle_register),
194                     service);
195
196   /* implement the Deregister() handler */
197   g_signal_connect (service->interface, "handle-deregister",
198                     G_CALLBACK (la_handler_service_handle_deregister),
199                     service);
200 }
201
202
203
204 static void
205 la_handler_service_finalize (GObject *object)
206 {
207   LAHandlerService *service = LA_HANDLER_SERVICE (object);
208
209   /* release the bus name */
210   g_bus_unown_name (service->bus_name_id);
211
212   /* release the D-Bus connection object */
213   if (service->connection != NULL)
214     g_object_unref (service->connection);
215
216   /* release the interface skeleton */
217   g_signal_handlers_disconnect_matched (service->interface,
218                                         G_SIGNAL_MATCH_DATA,
219                                         0, 0, NULL, NULL, service);
220   g_object_unref (service->interface);
221
222   /* release the job manager skeleton */
223   g_object_unref (service->job_manager);
224
225   /* release the shutdown consumers */
226   g_hash_table_destroy (service->units_to_consumers);
227   g_hash_table_destroy (service->consumers_to_units);
228
229   (*G_OBJECT_CLASS (la_handler_service_parent_class)->finalize) (object);
230 }
231
232
233
234 static void
235 la_handler_service_get_property (GObject    *object,
236                                  guint       prop_id,
237                                  GValue     *value,
238                                  GParamSpec *pspec)
239 {
240   LAHandlerService *service = LA_HANDLER_SERVICE (object);
241
242   switch (prop_id)
243     {
244     case PROP_CONNECTION:
245       g_value_set_object (value, service->connection);
246       break;
247     case PROP_JOB_MANAGER:
248       g_value_set_object (value, service->job_manager);
249       break;
250     default:
251       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
252       break;
253     }
254 }
255
256
257
258 static void
259 la_handler_service_set_property (GObject      *object,
260                                  guint         prop_id,
261                                  const GValue *value,
262                                  GParamSpec   *pspec)
263 {
264   LAHandlerService *service = LA_HANDLER_SERVICE (object);
265
266   switch (prop_id)
267     {
268     case PROP_CONNECTION:
269       service->connection = g_value_dup_object (value);
270       break;
271     case PROP_JOB_MANAGER:
272       service->job_manager = g_value_dup_object (value);
273       break;
274     default:
275       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
276       break;
277     }
278 }
279
280
281
282 static gboolean
283 la_handler_service_handle_register (LAHandler             *interface,
284                                     GDBusMethodInvocation *invocation,
285                                     const gchar           *unit,
286                                     const gchar           *mode,
287                                     guint                  timeout,
288                                     LAHandlerService      *service)
289 {
290   /* delegate registration of the legacy app to a more generalised function */
291   la_handler_service_register (service, unit, mode, timeout,
292                                (GAsyncReadyCallback) la_handler_service_handle_register_finish, invocation);
293
294   return TRUE;
295 }
296
297
298
299 static void
300 la_handler_service_handle_register_finish (NSMConsumer           *nsm_consumer,
301                                            GAsyncResult          *res,
302                                            GDBusMethodInvocation *invocation)
303 {
304   GError *error = NULL;
305   gchar  *log_text;
306   gint    error_code;
307
308   nsm_consumer_call_register_shutdown_client_finish (nsm_consumer, &error_code, res,
309                                                      &error);
310   if (error != NULL)
311     {
312       log_text = g_strdup_printf ("Error occurred registering legacy app: %s",
313                                   error->message);
314       DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
315       g_free (log_text);
316       g_error_free (error);
317     }
318
319   /* notify the caller that we have handled the registration request */
320   g_dbus_method_invocation_return_value (invocation, NULL);
321 }
322
323
324
325 static gboolean
326 la_handler_service_handle_deregister (LAHandler             *object,
327                                       GDBusMethodInvocation *invocation,
328                                       const gchar           *unit,
329                                       LAHandlerService      *service)
330 {
331   /* notify the caller that we have handled the registration request */
332   g_dbus_method_invocation_return_value (invocation, NULL);
333   return TRUE;
334 }
335
336
337
338 static void
339 la_handler_service_handle_consumer_lifecycle_request (ShutdownConsumer      *interface,
340                                                       GDBusMethodInvocation *invocation,
341                                                       guint                  request,
342                                                       guint                  request_id,
343                                                       LAHandlerService      *service)
344 {
345   GVariant *return_type;
346   gchar    *unit_name = g_hash_table_lookup (service->consumers_to_units, interface);
347
348   /* call job_manager_stop */
349   job_manager_stop (service->job_manager, unit_name, NULL,
350                     la_handler_service_handle_consumer_lifecycle_request_finish,
351                     GUINT_TO_POINTER (request_id));
352   
353   /* returns for the invocation (with error code) */
354   return_type = g_variant_new_int32 (1); /* bare number because enum comes later */
355   g_dbus_method_invocation_return_value (invocation, return_type);
356   g_variant_unref (return_type);
357 }
358
359
360
361 static void
362 la_handler_service_handle_consumer_lifecycle_request_finish (JobManager  *manager,
363                                                              const gchar *unit,
364                                                              const gchar *result,
365                                                              GError      *error,
366                                                              gpointer     user_data)
367 {
368   gchar *log_text;
369
370   /* log any errors */
371   if (error != NULL)
372     {
373       log_text = g_strdup_printf ("Error occurred handling lifecycle request: %s",
374                                   error->message);
375       DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
376       g_free (log_text);
377     }
378
379   if (g_strcmp0 (result, "failed") == 0)
380     {
381       DLT_LOG (la_handler_context, DLT_LOG_ERROR,
382                DLT_STRING ("Error occurred handling lifecycle request"));
383     }
384
385 }
386
387
388
389 LAHandlerService *
390 la_handler_service_new (GDBusConnection *connection,
391                         JobManager      *job_manager)
392 {
393   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
394   g_return_val_if_fail (IS_JOB_MANAGER (job_manager), NULL);
395
396   return g_object_new (LA_HANDLER_TYPE_SERVICE,
397                        "connection", connection,
398                        "job-manager", job_manager,
399                        NULL);
400 }
401
402
403 gboolean
404 la_handler_service_start (LAHandlerService *service,
405                            GError           **error)
406 {
407   g_return_val_if_fail (LA_HANDLER_IS_SERVICE (service), FALSE);
408   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
409
410   /* announce the org.genivi.BootManager1.LegacyAppHandler service on the bus */
411   return g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (service->interface),
412                                            service->connection,
413                                            "/org/genivi/BootManager1/LegacyAppHandler",
414                                            error);
415 }
416
417
418
419 void
420 la_handler_service_register (LAHandlerService   *service,
421                              const gchar        *unit,
422                              const gchar        *mode,
423                              guint               timeout,
424                              GAsyncReadyCallback callback,
425                              gpointer            user_data)
426 {
427   ShutdownConsumer *consumer;
428   GError           *error = NULL;
429   gchar            *log_text;
430   gchar            *object_path;
431
432   g_return_if_fail (LA_HANDLER_IS_SERVICE (service));
433   g_return_if_fail (unit != NULL && *unit != '\0');
434   g_return_if_fail (mode != NULL && *mode != '\0');
435
436   /* find out if this unit is already registered with a shutdown consumer */
437   if (g_hash_table_lookup (service->units_to_consumers, unit))
438     return;
439
440   /* create a new ShutdownConsumer and store it in service */
441   consumer = shutdown_consumer_skeleton_new ();
442   g_hash_table_insert (service->units_to_consumers, g_strdup (unit),
443                        g_object_ref (consumer));
444   g_hash_table_insert (service->consumers_to_units, g_object_ref (consumer),
445                        g_strdup (unit));
446   service->index++;
447
448   /* set up signal handling and skeleton exporting */
449   object_path = g_strdup_printf ("%s/%u", service->prefix, service->index);
450   g_signal_connect (consumer, "handle-lifecycle-request",
451                     G_CALLBACK (la_handler_service_handle_consumer_lifecycle_request),
452                     service);
453   g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (consumer),
454                                     service->connection, object_path, &error);
455   if (error != NULL)
456     {
457       log_text = 
458         g_strdup_printf ("Error exporting shutdown consumer interface skeleton: %s",
459                          error->message);
460       DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
461       g_free (log_text);
462       g_error_free (error);
463     }
464
465   /* register the shutdown consumer with the NSM Consumer */
466   nsm_consumer_call_register_shutdown_client (service->nsm_consumer,
467                                               "org.genivi.BootManager1", object_path, 0,
468                                               timeout, NULL, callback, user_data);
469
470   g_free (object_path);
471 }