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>
19 #include <common/nsm-consumer-dbus.h>
20 #include <common/shutdown-consumer-dbus.h>
22 #include <boot-manager/job-manager.h>
23 #include <boot-manager/la-handler-dbus.h>
24 #include <boot-manager/la-handler-service.h>
28 DLT_IMPORT_CONTEXT (la_handler_context);
32 /* property identifiers */
42 typedef struct _LAHandlerServiceData LAHandlerServiceData;
46 static void la_handler_service_constructed (GObject *object);
47 static void la_handler_service_finalize (GObject *object);
48 static void la_handler_service_get_property (GObject *object,
52 static void la_handler_service_set_property (GObject *object,
56 static gboolean la_handler_service_handle_register (LAHandler *interface,
57 GDBusMethodInvocation *invocation,
61 LAHandlerService *service);
62 static void la_handler_service_handle_register_finish (GObject *object,
65 static void la_handler_service_handle_consumer_lifecycle_request (ShutdownConsumer *interface,
66 GDBusMethodInvocation *invocation,
69 LAHandlerService *service);
70 static void la_handler_service_handle_consumer_lifecycle_request_finish (JobManager *manager,
75 static LAHandlerServiceData *la_handler_service_data_new (LAHandlerService *service,
76 GDBusMethodInvocation *invocation,
78 static void la_handler_service_data_unref (LAHandlerServiceData *data);
82 struct _LAHandlerServiceClass
84 GObjectClass __parent__;
87 struct _LAHandlerService
91 GDBusConnection *connection;
93 JobManager *job_manager;
95 /* Associations of shutdown consumers and their units */
96 GHashTable *units_to_consumers;
97 GHashTable *consumers_to_units;
103 /* connection to the NSM consumer interface */
104 NSMConsumer *nsm_consumer;
107 struct _LAHandlerServiceData
109 GDBusMethodInvocation *invocation;
110 LAHandlerService *service;
116 G_DEFINE_TYPE (LAHandlerService, la_handler_service, G_TYPE_OBJECT);
121 la_handler_service_class_init (LAHandlerServiceClass *klass)
123 GObjectClass *gobject_class;
125 gobject_class = G_OBJECT_CLASS (klass);
126 gobject_class->constructed = la_handler_service_constructed;
127 gobject_class->finalize = la_handler_service_finalize;
128 gobject_class->get_property = la_handler_service_get_property;
129 gobject_class->set_property = la_handler_service_set_property;
131 g_object_class_install_property (gobject_class,
133 g_param_spec_object ("connection",
136 G_TYPE_DBUS_CONNECTION,
138 G_PARAM_CONSTRUCT_ONLY |
139 G_PARAM_STATIC_STRINGS));
140 g_object_class_install_property (gobject_class,
142 g_param_spec_object ("job-manager",
144 "The internal handler of Start()"
148 G_PARAM_CONSTRUCT_ONLY |
149 G_PARAM_STATIC_STRINGS));
155 la_handler_service_constructed (GObject *object)
157 LAHandlerService *service = LA_HANDLER_SERVICE (object);
158 GError *error = NULL;
161 /* connect to the node state manager */
162 service->nsm_consumer =
163 nsm_consumer_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,
164 "com.contiautomotive.NodeStateManager",
165 "/com/contiautomotive/NodeStateManager/Consumer",
169 log_text = g_strdup_printf ("Error occurred connecting to NSM Consumer: %s",
171 DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
173 g_error_free (error);
180 la_handler_service_init (LAHandlerService *service)
182 service->interface = la_handler_skeleton_new ();
184 /* the number that follows the prefix in the shutdown consumer's object path,
185 * making every shutdown consumer unique */
188 /* the string that precedes the index in the shutdown consumer's object path */
189 service->prefix = "/org/genivi/BootManager1/ShutdownConsumer";
191 /* initialize the association of shutdown consumers to units */
192 service->units_to_consumers = g_hash_table_new_full (g_str_hash, g_str_equal,
193 (GDestroyNotify) g_free,
194 (GDestroyNotify) g_object_unref);
195 service->consumers_to_units = g_hash_table_new_full (g_direct_hash, g_direct_equal,
196 (GDestroyNotify) g_object_unref,
197 (GDestroyNotify) g_free);
199 /* implement the Register() handler */
200 g_signal_connect (service->interface, "handle-register",
201 G_CALLBACK (la_handler_service_handle_register),
208 la_handler_service_finalize (GObject *object)
210 LAHandlerService *service = LA_HANDLER_SERVICE (object);
212 /* release the bus name */
213 g_bus_unown_name (service->bus_name_id);
215 /* release the D-Bus connection object */
216 if (service->connection != NULL)
217 g_object_unref (service->connection);
219 /* release the interface skeleton */
220 g_signal_handlers_disconnect_matched (service->interface,
222 0, 0, NULL, NULL, service);
223 g_object_unref (service->interface);
225 /* release the job manager skeleton */
226 g_object_unref (service->job_manager);
228 /* release the shutdown consumers */
229 g_hash_table_unref (service->units_to_consumers);
230 g_hash_table_unref (service->consumers_to_units);
232 (*G_OBJECT_CLASS (la_handler_service_parent_class)->finalize) (object);
238 la_handler_service_get_property (GObject *object,
243 LAHandlerService *service = LA_HANDLER_SERVICE (object);
247 case PROP_CONNECTION:
248 g_value_set_object (value, service->connection);
250 case PROP_JOB_MANAGER:
251 g_value_set_object (value, service->job_manager);
254 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
262 la_handler_service_set_property (GObject *object,
267 LAHandlerService *service = LA_HANDLER_SERVICE (object);
271 case PROP_CONNECTION:
272 service->connection = g_value_dup_object (value);
274 case PROP_JOB_MANAGER:
275 service->job_manager = g_value_dup_object (value);
278 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
286 la_handler_service_handle_register (LAHandler *interface,
287 GDBusMethodInvocation *invocation,
291 LAHandlerService *service)
293 ShutdownConsumer *consumer;
294 GError *error = NULL;
298 g_return_val_if_fail (IS_LA_HANDLER (interface), FALSE);
299 g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), FALSE);
300 g_return_val_if_fail (unit != NULL && *unit != '\0', FALSE);
301 g_return_val_if_fail (mode != NULL && *mode != '\0', FALSE);
302 g_return_val_if_fail (LA_HANDLER_IS_SERVICE (service), FALSE);
304 /* find out if this unit is already registered with a shutdown consumer */
305 if (g_hash_table_lookup (service->units_to_consumers, unit))
307 /* there already is a shutdown consumer for the unit, so ignore this request */
308 la_handler_complete_register (interface, invocation);
312 /* create a new ShutdownConsumer and implement its LifecycleRequest method */
313 consumer = shutdown_consumer_skeleton_new ();
314 g_signal_connect (consumer, "handle-lifecycle-request",
315 G_CALLBACK (la_handler_service_handle_consumer_lifecycle_request),
318 /* associate the shutdown consumer with the unit name */
319 g_hash_table_insert (service->units_to_consumers, g_strdup (unit),
320 g_object_ref (consumer));
321 g_hash_table_insert (service->consumers_to_units, g_object_ref (consumer),
324 /* export the shutdown consumer on the bus */
325 object_path = g_strdup_printf ("%s/%u", service->prefix, service->index);
326 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (consumer),
327 service->connection, object_path, &error);
331 g_strdup_printf ("Failed to export shutdown consumer on the bus: %s",
333 DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
335 g_error_free (error);
338 /* temporarily store a reference to the LAHandlerService in the invocation object */
339 g_object_set_data_full (G_OBJECT (invocation), "la-handler-service",
340 g_object_ref (service), (GDestroyNotify) g_object_unref);
342 /* register the shutdown consumer with the NSM Consumer */
343 nsm_consumer_call_register_shutdown_client (service->nsm_consumer,
344 "org.genivi.BootManager1", object_path, 0,
346 la_handler_service_handle_register_finish,
349 g_free (object_path);
351 /* increment the counter for our shutdown consumer object paths */
360 la_handler_service_handle_register_finish (GObject *object,
364 GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (user_data);
365 LAHandlerService *service;
366 NSMConsumer *nsm_consumer = NSM_CONSUMER (object);
367 GError *error = NULL;
371 g_return_if_fail (IS_NSM_CONSUMER (nsm_consumer));
372 g_return_if_fail (G_IS_ASYNC_RESULT (res));
373 g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
375 /* finish registering the shutdown client */
376 nsm_consumer_call_register_shutdown_client_finish (nsm_consumer, &error_code, res,
380 log_text = g_strdup_printf ("Failed to register a shutdown consumer: %s",
382 DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
384 g_error_free (error);
387 /* retrieve the LAHandlerService from the invocation object */
388 service = g_object_get_data (G_OBJECT (invocation), "la-handler-service");
390 /* notify the caller that we have handled the registration request */
391 la_handler_complete_register (service->interface, invocation);
397 la_handler_service_handle_consumer_lifecycle_request (ShutdownConsumer *consumer,
398 GDBusMethodInvocation *invocation,
401 LAHandlerService *service)
403 LAHandlerServiceData *data;
406 g_return_if_fail (IS_SHUTDOWN_CONSUMER (consumer));
407 g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
408 g_return_if_fail (LA_HANDLER_IS_SERVICE (service));
410 /* look up the unit name associated with this shutdown consumer */
411 unit_name = g_hash_table_lookup (service->consumers_to_units, consumer);
413 if (unit_name != NULL)
415 data = la_handler_service_data_new (service, NULL, request_id);
417 /* stop this unit now */
418 job_manager_stop (service->job_manager, unit_name, NULL,
419 la_handler_service_handle_consumer_lifecycle_request_finish,
422 /* let the NSM know that we are working on this request */
423 shutdown_consumer_complete_lifecycle_request (consumer, invocation, 7);
427 /* NSM asked us to shutdown a shutdown consumer we did not register;
428 * make it aware by returning an error */
429 shutdown_consumer_complete_lifecycle_request (consumer, invocation, 2);
436 la_handler_service_handle_consumer_lifecycle_request_finish (JobManager *manager,
442 LAHandlerServiceData *data = (LAHandlerServiceData *)user_data;
447 g_return_if_fail (IS_JOB_MANAGER (manager));
448 g_return_if_fail (unit != NULL && *unit != '\0');
449 g_return_if_fail (result != NULL && *result != '\0');
450 g_return_if_fail (data != NULL);
452 /* log an error if shutting down the consumer has failed */
455 log_text = g_strdup_printf ("Failed to shutdown a shutdown consumer: %s",
457 DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
460 /* send an error back to the NSM */
464 /* log an error if systemd failed to stop the consumer */
465 if (g_strcmp0 (result, "failed") == 0)
467 DLT_LOG (la_handler_context, DLT_LOG_ERROR,
468 DLT_STRING ("Failed to shutdown a shutdown consumer"));
470 /* send an error back to the NSM */
474 /* let the NSM know that we have handled the lifecycle request */
475 if (!nsm_consumer_call_lifecycle_request_complete_sync (data->service->nsm_consumer,
476 data->request_id, status,
479 log_text = g_strdup_printf ("Failed to notify Node State Manager about completed "
480 "lifecycle request: %s", err->message);
481 DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
486 la_handler_service_data_unref (data);
491 static LAHandlerServiceData *
492 la_handler_service_data_new (LAHandlerService *service,
493 GDBusMethodInvocation *invocation,
496 LAHandlerServiceData *data;
498 data = g_slice_new0 (LAHandlerServiceData);
500 data->service = g_object_ref (service);
501 if (invocation != NULL)
502 data->invocation = g_object_ref (invocation);
503 data->request_id = request_id;
511 la_handler_service_data_unref (LAHandlerServiceData *data)
516 if (data->invocation != NULL)
517 g_object_unref (data->invocation);
518 if (data->service != NULL)
519 g_object_unref (data->service);
520 g_slice_free (LAHandlerServiceData, data);
526 la_handler_service_new (GDBusConnection *connection,
527 JobManager *job_manager)
529 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
530 g_return_val_if_fail (IS_JOB_MANAGER (job_manager), NULL);
532 return g_object_new (LA_HANDLER_TYPE_SERVICE,
533 "connection", connection,
534 "job-manager", job_manager,
540 la_handler_service_start (LAHandlerService *service,
543 g_return_val_if_fail (LA_HANDLER_IS_SERVICE (service), FALSE);
544 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
546 /* announce the org.genivi.BootManager1.LegacyAppHandler service on the bus */
547 return g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (service->interface),
549 "/org/genivi/BootManager1/LegacyAppHandler",