power-internal: Add getter and signal subscriber for lock count
[platform/core/api/device.git] / src / power-internal.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <gio/gio.h>
5 #include <glib.h>
6
7 #include <libsyscommon/libgdbus.h>
8 #include <libsyscommon/list.h>
9 #include <hal/hal-device-board.h>
10
11 #include "power-internal.h"
12 #include "common.h"
13
14 #define DBUS_METHOD_SYNC_CALL_TIMEOUT_MS    10000 /* 10 second */
15 #define DEVICE_POWER_LOCK_MAX_INDEX             (POWER_LOCK_DISPLAY_DIM + 1)
16
17 #define LSB_INDEX(val)                  (__builtin_ctzll(val))
18 #define IS_IN_BETWEEN(val, le, gt)      (((le) <= (val) && (val) < (gt)))
19 #define IS_STATE_BIT(bit)               IS_IN_BETWEEN(bit, \
20                                                       (1ULL << DEVICE_POWER_STATE_MIN_INDEX), \
21                                                       (1ULL << DEVICE_POWER_STATE_MAX_INDEX))
22 #define IS_TRANSIENT_STATE_BIT(bit)     IS_IN_BETWEEN(bit, \
23                                                       (1ULL << DEVICE_POWER_TRANSIENT_STATE_MIN_INDEX), \
24                                                       (1ULL << DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX))
25
26 enum {
27         DEVICE_POWER_STATE_START_INDEX          = LSB_INDEX(DEVICE_POWER_STATE_START),
28         DEVICE_POWER_STATE_NORMAL_INDEX         = LSB_INDEX(DEVICE_POWER_STATE_NORMAL),
29         DEVICE_POWER_STATE_SLEEP_INDEX          = LSB_INDEX(DEVICE_POWER_STATE_SLEEP),
30         DEVICE_POWER_STATE_POWEROFF_INDEX       = LSB_INDEX(DEVICE_POWER_STATE_POWEROFF),
31         DEVICE_POWER_STATE_REBOOT_INDEX         = LSB_INDEX(DEVICE_POWER_STATE_REBOOT),
32         DEVICE_POWER_STATE_EXIT_INDEX           = LSB_INDEX(DEVICE_POWER_STATE_EXIT),
33         /* add state here */
34
35         DEVICE_POWER_STATE_MAX_INDEX,
36         DEVICE_POWER_STATE_MIN_INDEX = DEVICE_POWER_STATE_START_INDEX,
37 };
38
39 enum {
40         DEVICE_POWER_TRANSIENT_STATE_RESUMING_EARLY_INDEX       = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_RESUMING_EARLY),
41         DEVICE_POWER_TRANSIENT_STATE_RESUMING_INDEX             = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_RESUMING),
42         DEVICE_POWER_TRANSIENT_STATE_RESUMING_LATE_INDEX        = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_RESUMING_LATE),
43         DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_EARLY_INDEX     = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_EARLY),
44         DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_INDEX           = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_SUSPENDING),
45         DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_LATE_INDEX      = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_LATE),
46         /* add transient state here */
47
48         DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX,
49         DEVICE_POWER_TRANSIENT_STATE_MIN_INDEX = DEVICE_POWER_TRANSIENT_STATE_RESUMING_EARLY_INDEX,
50 };
51
52 static int state_signal_id[DEVICE_POWER_STATE_MAX_INDEX];
53 static int transient_state_signal_id[DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX];
54 static int power_lock_state_callback_signal_subscription_id[DEVICE_POWER_LOCK_MAX_INDEX];
55 static int power_lock_count_callback_signal_subscription_id[DEVICE_POWER_LOCK_MAX_INDEX];
56 static GList *power_lock_state_callback_list[DEVICE_POWER_LOCK_MAX_INDEX];
57 static GList *power_lock_count_callback_list[DEVICE_POWER_LOCK_MAX_INDEX];
58
59 struct power_wait_handler {
60         union {
61                 device_power_state_wait_callback state_wait_callback;
62                 device_power_transient_state_wait_callback transient_state_wait_callback;
63         };
64         void *user_data;
65 };
66
67 struct power_change_state_handler {
68         device_power_change_state_callback callback;
69         void *user_data;
70         uint64_t state;
71 };
72
73 struct power_lock_state_change_callback_handler {
74         device_power_lock_state_change_callback callback;
75         void *data;
76 };
77
78 //LCOV_EXCL_START Internal function
79 struct power_lock_count_change_callback_handler {
80         device_power_lock_count_change_callback callback;
81         void *data;
82 };
83
84 static bool power_is_valid_power_lock_type(power_lock_e power_lock_type)
85 {
86         switch(power_lock_type) {
87         case POWER_LOCK_CPU:
88         case POWER_LOCK_DISPLAY:
89         case POWER_LOCK_DISPLAY_DIM:
90                 return true;
91         default:
92                 return false;
93         }
94 }
95
96 static void signal_unsubscribed_callback(void *data)
97 {
98         struct power_wait_handler *h = (struct power_wait_handler *) data;
99
100         free(h);
101 }
102
103 static void state_signal_callback(GDBusConnection *connection,
104         const gchar *sender_name,
105         const gchar *object_path,
106         const gchar *interface_name,
107         const gchar *signal_name,
108         GVariant *parameters,
109         gpointer user_data)
110 {
111         struct power_wait_handler *h;
112         uint64_t prev_state, next_state, id;
113         int reason;
114
115         h = (struct power_wait_handler *) user_data;
116
117         assert(h->state_wait_callback);
118
119         g_variant_get(parameters, "(ttti)", &prev_state, &next_state, &id, &reason);
120
121         h->state_wait_callback((unsigned int)prev_state, (unsigned int)next_state, id, reason, h->user_data);
122 }
123
124 static int __register_state_signal_callback(GDBusConnection *connection,
125         int index, device_power_state_wait_callback cb, void *data)
126 {
127         static const char *signame[DEVICE_POWER_STATE_MAX_INDEX] = {
128                 [DEVICE_POWER_STATE_START_INDEX]                      = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_START,
129                 [DEVICE_POWER_STATE_NORMAL_INDEX]                     = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_NORMAL,
130                 [DEVICE_POWER_STATE_SLEEP_INDEX]                      = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SLEEP,
131                 [DEVICE_POWER_STATE_POWEROFF_INDEX]                   = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_POWEROFF,
132                 [DEVICE_POWER_STATE_REBOOT_INDEX]                     = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_REBOOT,
133                 [DEVICE_POWER_STATE_EXIT_INDEX]                       = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_EXIT,
134         };
135
136         struct power_wait_handler *h;
137
138         assert(state_signal_id[index] == 0);
139
140         h = malloc(sizeof(struct power_wait_handler));
141         if (!h) {
142                 _E("Failed to alloc user data");
143                 return DEVICE_ERROR_OPERATION_FAILED;
144         }
145
146         h->state_wait_callback = cb;
147         h->user_data = data;
148
149         state_signal_id[index] = g_dbus_connection_signal_subscribe(connection,
150                 DEVICED_BUS_NAME,
151                 DEVICED_INTERFACE_POWER,
152                 signame[index],
153                 DEVICED_PATH_POWER,
154                 NULL,
155                 G_DBUS_SIGNAL_FLAGS_NONE,
156                 state_signal_callback,
157                 h,
158                 signal_unsubscribed_callback);
159
160         return DEVICE_ERROR_NONE;
161 }
162
163 static int register_state_signal_callback(uint64_t states, device_power_state_wait_callback cb, void *data)
164 {
165         GDBusConnection *connection;
166         GVariant *retgv = NULL;
167         GError *err = NULL;
168
169         if (states == 0)
170                 return DEVICE_ERROR_NONE;
171
172         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
173         if (!connection) {
174                 _E("Failed to get dbus connection, %s", err->message);
175                 g_clear_error(&err);
176                 return DEVICE_ERROR_OPERATION_FAILED;
177         }
178
179         // add change state wait
180         retgv = g_dbus_connection_call_sync(connection,
181                         DEVICED_BUS_NAME,
182                         DEVICED_PATH_POWER,
183                         DEVICED_INTERFACE_POWER,
184                         "AddChangeStateWait",
185                         g_variant_new("(t)", states),
186                         NULL,
187                         G_DBUS_CALL_FLAGS_NONE,
188                         DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
189                         NULL,
190                         &err);
191         if (!retgv || err) {
192                 _E("Failed to request AddChangeStateWait, %s", err->message);
193                 g_error_free(err);
194                 return DEVICE_ERROR_OPERATION_FAILED;
195         }
196
197         // subscribe signal
198         for (int index = DEVICE_POWER_STATE_MIN_INDEX; index < DEVICE_POWER_STATE_MAX_INDEX; ++index)
199                 if((states & (1ULL << index)) && (state_signal_id[index] == 0))
200                         __register_state_signal_callback(connection, index, cb, data);
201
202         return DEVICE_ERROR_NONE;
203 }
204
205 int device_power_add_state_wait_callback(device_power_state_e state_bits,
206         device_power_state_wait_callback cb, void *data)
207 {
208         if (!IS_STATE_BIT(state_bits))
209                 return DEVICE_ERROR_INVALID_PARAMETER;
210
211         if (!cb)
212                 return DEVICE_ERROR_INVALID_PARAMETER;
213
214         return register_state_signal_callback(state_bits, cb, data);
215 }
216
217 static void transient_state_signal_callback(GDBusConnection *connection,
218         const gchar *sender_name,
219         const gchar *object_path,
220         const gchar *interface_name,
221         const gchar *signal_name,
222         GVariant *parameters,
223         gpointer user_data)
224 {
225         struct power_wait_handler *h;
226         uint64_t prev_state, next_state, id;
227         int reason;
228
229         h = (struct power_wait_handler *) user_data;
230
231         assert(h->transient_state_wait_callback);
232
233         g_variant_get(parameters, "(ttti)", &prev_state, &next_state, &id, &reason);
234
235         h->transient_state_wait_callback((unsigned int)next_state, id, reason, h->user_data);
236 }
237
238 static int __register_transient_state_signal_callback(GDBusConnection *connection,
239         int index, device_power_transient_state_wait_callback cb, void *data)
240 {
241         static const char *signame[DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX] = {
242                 [DEVICE_POWER_TRANSIENT_STATE_RESUMING_EARLY_INDEX]     = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_EARLY,
243                 [DEVICE_POWER_TRANSIENT_STATE_RESUMING_INDEX]           = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING,
244                 [DEVICE_POWER_TRANSIENT_STATE_RESUMING_LATE_INDEX]      = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_LATE,
245                 [DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_EARLY_INDEX]   = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_EARLY,
246                 [DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_INDEX]         = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING,
247                 [DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_LATE_INDEX]    = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_LATE,
248         };
249
250         struct power_wait_handler *h;
251
252         assert(transient_state_signal_id[index] == 0);
253
254         h = malloc(sizeof(struct power_wait_handler));
255         if (!h) {
256                 _E("Failed to alloc user data");
257                 return DEVICE_ERROR_OPERATION_FAILED;
258         }
259
260         h->transient_state_wait_callback = cb;
261         h->user_data = data;
262
263         transient_state_signal_id[index] = g_dbus_connection_signal_subscribe(connection,
264                 DEVICED_BUS_NAME,
265                 DEVICED_INTERFACE_POWER,
266                 signame[index],
267                 DEVICED_PATH_POWER,
268                 NULL,
269                 G_DBUS_SIGNAL_FLAGS_NONE,
270                 transient_state_signal_callback,
271                 h,
272                 signal_unsubscribed_callback);
273
274         return DEVICE_ERROR_NONE;
275 }
276
277 static int register_transient_state_signal_callback(uint64_t states, device_power_transient_state_wait_callback cb, void *data)
278 {
279         GDBusConnection *connection;
280         GVariant *retgv = NULL;
281         GError *err = NULL;
282
283         if (states == 0)
284                 return DEVICE_ERROR_NONE;
285
286         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
287         if (!connection) {
288                 _E("Failed to get dbus connection, %s", err->message);
289                 g_clear_error(&err);
290                 return DEVICE_ERROR_OPERATION_FAILED;
291         }
292
293         // add change state wait
294         retgv = g_dbus_connection_call_sync(connection,
295                         DEVICED_BUS_NAME,
296                         DEVICED_PATH_POWER,
297                         DEVICED_INTERFACE_POWER,
298                         "AddChangeTransientStateWait",
299                         g_variant_new("(t)", states),
300                         NULL,
301                         G_DBUS_CALL_FLAGS_NONE,
302                         DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
303                         NULL,
304                         &err);
305         if (!retgv || err) {
306                 _E("Failed to request AddChangeTransientStateWait, %s", err->message);
307                 g_error_free(err);
308                 return DEVICE_ERROR_OPERATION_FAILED;
309         }
310
311         // subscribe signal
312         for (int index = DEVICE_POWER_TRANSIENT_STATE_MIN_INDEX; index < DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX; ++index)
313                 if((states & (1ULL << index)) && (transient_state_signal_id[index] == 0))
314                         __register_transient_state_signal_callback(connection, index, cb, data);
315
316         return DEVICE_ERROR_NONE;
317 }
318
319 int device_power_add_transient_state_wait_callback(device_power_transient_state_e transient_bits,
320         device_power_transient_state_wait_callback cb, void *data)
321 {
322         if (!IS_TRANSIENT_STATE_BIT(transient_bits))
323                 return DEVICE_ERROR_INVALID_PARAMETER;
324
325         if (!cb)
326                 return DEVICE_ERROR_INVALID_PARAMETER;
327
328         return register_transient_state_signal_callback(transient_bits, cb, data);
329 }
330
331 int device_power_confirm_wait_callback(uint64_t wait_callback_id)
332 {
333         GDBusConnection *connection;
334         GVariant *retgv;
335         GError *err = NULL;
336         int ret;
337
338         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
339         if (!connection) {
340                 _E("Failed to get dbus connection, %s", err->message);
341                 g_clear_error(&err);
342                 return DEVICE_ERROR_OPERATION_FAILED;
343         }
344
345         retgv = g_dbus_connection_call_sync(connection,
346                 DEVICED_BUS_NAME,
347                 DEVICED_PATH_POWER,
348                 DEVICED_INTERFACE_POWER,
349                 "ConfirmChangeStateWait",
350                 g_variant_new("(t)", wait_callback_id),
351                 NULL,
352                 G_DBUS_CALL_FLAGS_NONE,
353                 DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
354                 NULL,
355                 &err);
356         if (!retgv || err) {
357                         _E("Failed to request ConfirmChangeStateWait, %s", err->message);
358                         g_error_free(err);
359                 return DEVICE_ERROR_OPERATION_FAILED;
360         }
361
362         g_variant_get(retgv, "(i)", &ret);
363         g_variant_unref(retgv);
364         if (ret != 0)
365                 return DEVICE_ERROR_OPERATION_FAILED;
366
367         return DEVICE_ERROR_NONE;
368 }
369
370 int device_power_cancel_wait_callback(uint64_t wait_callback_id)
371 {
372         GDBusConnection *connection;
373         GVariant *retgv;
374         GError *err = NULL;
375         int ret;
376
377         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
378         if (!connection) {
379                 _E("Failed to get dbus connection, %s", err->message);
380                 g_clear_error(&err);
381                 return DEVICE_ERROR_OPERATION_FAILED;
382         }
383
384         retgv = g_dbus_connection_call_sync(connection,
385                 DEVICED_BUS_NAME,
386                 DEVICED_PATH_POWER,
387                 DEVICED_INTERFACE_POWER,
388                 "CancelChangeStateWait",
389                 g_variant_new("(t)", wait_callback_id),
390                 NULL,
391                 G_DBUS_CALL_FLAGS_NONE,
392                 DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
393                 NULL,
394                 &err);
395         if (!retgv || err) {
396                         _E("Failed to request ConfirmChangeStateWait, %s", err->message);
397                         g_error_free(err);
398                 return DEVICE_ERROR_OPERATION_FAILED;
399         }
400
401         g_variant_get(retgv, "(i)", &ret);
402         g_variant_unref(retgv);
403         if (ret != 0)
404                 return DEVICE_ERROR_OPERATION_FAILED;
405
406         return DEVICE_ERROR_NONE;
407 }
408
409 static void  __unregister_state_signal_callback(GDBusConnection *connection, int index)
410 {
411         if (state_signal_id[index] == 0)
412                 return;
413
414         g_dbus_connection_signal_unsubscribe(connection, state_signal_id[index]);
415         state_signal_id[index] = 0;
416 }
417
418 static void unregister_state_signal_callback(uint64_t states)
419 {
420         GError *err = NULL;
421         GDBusConnection *connection;
422
423         if (states == 0)
424                 return;
425
426         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
427         if (!connection) {
428                 _E("Failed to get dbus connection, %s", err->message);
429                 g_clear_error(&err);
430                 return;
431         }
432
433         // unsubscribe signal
434         for (int index = DEVICE_POWER_STATE_MIN_INDEX; index < DEVICE_POWER_STATE_MAX_INDEX; ++index)
435                 if((states & (1ULL << index)) && (state_signal_id[index] > 0))
436                         __unregister_state_signal_callback(connection, index);
437
438         //remove change state wait
439         g_dbus_connection_call_sync(connection,
440                 DEVICED_BUS_NAME,
441                 DEVICED_PATH_POWER,
442                 DEVICED_INTERFACE_POWER,
443                 "RemoveChangeStateWait",
444                 g_variant_new("(t)", states),
445                 NULL,
446                 G_DBUS_CALL_FLAGS_NONE,
447                 DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
448                 NULL,
449                 NULL);
450 }
451
452 void device_power_remove_state_wait_callback(device_power_state_e state_bits)
453 {
454         if (!IS_STATE_BIT(state_bits))
455                 return;
456
457         unregister_state_signal_callback(state_bits);
458 }
459
460 static void  __unregister_transient_state_signal_callback(GDBusConnection *connection, int index)
461 {
462         if (transient_state_signal_id[index] == 0)
463                 return;
464
465         g_dbus_connection_signal_unsubscribe(connection, transient_state_signal_id[index]);
466         transient_state_signal_id[index] = 0;
467 }
468
469 static void unregister_transient_state_signal_callback(uint64_t states)
470 {
471         GError *err = NULL;
472         GDBusConnection *connection;
473
474         if (states == 0)
475                 return;
476
477         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
478         if (!connection) {
479                 _E("Failed to get dbus connection, %s", err->message);
480                 g_clear_error(&err);
481                 return;
482         }
483
484         // unsubscribe signal
485         for (int index = DEVICE_POWER_TRANSIENT_STATE_MIN_INDEX; index < DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX; ++index)
486                 if((states & (1ULL << index)) && (transient_state_signal_id[index] > 0))
487                         __unregister_transient_state_signal_callback(connection, index);
488
489         //remove change state wait
490         g_dbus_connection_call_sync(connection,
491                 DEVICED_BUS_NAME,
492                 DEVICED_PATH_POWER,
493                 DEVICED_INTERFACE_POWER,
494                 "RemoveChangeTransientStateWait",
495                 g_variant_new("(t)", states),
496                 NULL,
497                 G_DBUS_CALL_FLAGS_NONE,
498                 DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
499                 NULL,
500                 NULL);
501 }
502
503 void device_power_remove_transient_state_wait_callback(device_power_transient_state_e transient_bits)
504 {
505         if (!IS_TRANSIENT_STATE_BIT(transient_bits))
506                 return;
507
508         unregister_transient_state_signal_callback(transient_bits);
509 }
510
511 static void change_state_async_callback(GObject *source_object, GAsyncResult *res, gpointer user_data)
512 {
513         GError *err = NULL;
514         GDBusConnection *connection;
515         GVariant *retgv;
516         int retval;
517         struct power_change_state_handler *h;
518
519         h = (struct power_change_state_handler *) user_data;
520         if (!h)
521                 return;
522
523         if (!h->callback)
524                 goto cleanup;
525
526         connection = (GDBusConnection *) source_object;
527         retgv = g_dbus_connection_call_finish(connection, res, &err);
528         if (err) {
529                 retval = -ECOMM;
530                 if (err->code == G_IO_ERROR_TIMED_OUT)
531                         retval = -ETIMEDOUT;
532
533                 _E("Failed to finish async call, %s(%d)", err->message, err->code);
534                 h->callback((unsigned int)h->state, retval, h->user_data);
535
536                 goto cleanup;
537         }
538
539         g_variant_get(retgv, "(i)", &retval);
540         h->callback((unsigned int)h->state, retval, h->user_data);
541
542 cleanup:
543         if (err)
544                 g_clear_error(&err);
545         free(h);
546 }
547
548 int device_power_change_state(device_power_state_e state, int timeout_sec, device_power_change_state_callback cb, void *user_data)
549 {
550         GError *err = NULL;
551         GDBusConnection *connection;
552         struct power_change_state_handler *h = NULL;
553
554         if (!IS_STATE_BIT(state))
555                 return DEVICE_ERROR_INVALID_PARAMETER;
556
557         if (!device_power_check_reboot_allowed()) {
558                 if (state == DEVICE_POWER_STATE_POWEROFF) {
559                         _E("Failed to Poweroff due to partition cloning.");
560                         return DEVICE_ERROR_OPERATION_FAILED;
561                 }
562
563                 if (state == DEVICE_POWER_STATE_REBOOT) {
564                         _E("Failed to Reboot due to partition cloning.");
565                         return DEVICE_ERROR_OPERATION_FAILED;
566                 }
567         }
568
569         if (cb) {
570                 h = (struct power_change_state_handler *) calloc(1, sizeof(struct power_change_state_handler));
571                 if (!h) {
572                         _E("Failed to alloc power_change_state_handler.");
573                         return DEVICE_ERROR_OPERATION_FAILED;
574                 }
575
576                 h->state = state;
577                 h->callback = cb;
578                 h->user_data = user_data;
579         }
580
581         if (timeout_sec <= 0)
582                 timeout_sec = 10;
583
584         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
585         if (!connection) {
586                 _E("Failed to get dbus connection, %s", err->message);
587                 g_clear_error(&err);
588                 free(h);
589                 return DEVICE_ERROR_OPERATION_FAILED;
590         }
591
592         g_dbus_connection_call(connection,
593                 DEVICED_BUS_NAME,
594                 DEVICED_PATH_POWER,
595                 DEVICED_INTERFACE_POWER,
596                 "PowerChangeState",
597                 g_variant_new("(t)", (uint64_t)state),
598                 NULL,
599                 G_DBUS_CALL_FLAGS_NONE,
600                 timeout_sec * 1000,
601                 NULL,
602                 change_state_async_callback,
603                 h);
604
605         return DEVICE_ERROR_NONE;
606 }
607
608 int device_power_check_reboot_allowed(void)
609 {
610         int retval, cloned;
611
612         retval = hal_device_board_get_partition_ab_cloned(&cloned);
613
614         return (retval != 0 || cloned != 0);
615 }
616
617 #ifndef EXCLUDE_INTERNAL_CAPI_SYSTEM_DEVICE
618 int device_power_get_wakeup_reason(device_power_transition_reason_e *reason)
619 {
620         int ret, reply;
621
622         if (!reason)
623                 return DEVICE_ERROR_INVALID_PARAMETER;
624
625         ret = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
626                 DEVICED_PATH_POWER,
627                 DEVICED_INTERFACE_POWER,
628                 "PowerGetWakeupReason",
629                 NULL,
630                 &reply);
631
632         if (ret < 0) {
633                 _E("Failed to call dbus method to get wakeup reason");
634                 return DEVICE_ERROR_OPERATION_FAILED;
635         }
636         *reason = reply;
637
638         return DEVICE_ERROR_NONE;
639 }
640 #endif
641
642 static void power_lock_state_change_cb(GDBusConnection *connection,
643         const gchar *sender_name,
644         const gchar *object_path,
645         const gchar *interface_name,
646         const gchar *signal_name,
647         GVariant *parameters,
648         gpointer user_data)
649 {
650         struct power_lock_state_change_callback_handler *callback_handler;
651         power_lock_e power_lock_type;
652         device_power_lock_state_e power_lock_state;
653         GList *callback_list, *elem, *elem_next;
654
655         g_variant_get(parameters, "(ii)", &power_lock_type, &power_lock_state);
656
657         callback_list = power_lock_state_callback_list[power_lock_type];
658         SYS_G_LIST_FOREACH_SAFE(callback_list, elem, elem_next, callback_handler)
659                 callback_handler->callback(power_lock_type,
660                         power_lock_state, callback_handler->data);
661 }
662
663 static void power_lock_count_change_cb(GDBusConnection *connection,
664         const gchar *sender_name,
665         const gchar *object_path,
666         const gchar *interface_name,
667         const gchar *signal_name,
668         GVariant *parameters,
669         gpointer user_data)
670 {
671         struct power_lock_count_change_callback_handler *callback_handler;
672         power_lock_e power_lock_type;
673         int power_lock_count;
674         GList *callback_list, *elem, *elem_next;
675
676         g_variant_get(parameters, "(ii)", &power_lock_type, &power_lock_count);
677
678         callback_list = power_lock_count_callback_list[power_lock_type];
679         SYS_G_LIST_FOREACH_SAFE(callback_list, elem, elem_next, callback_handler)
680                 callback_handler->callback(power_lock_type,
681                         power_lock_count, callback_handler->data);
682 }
683
684 static void destroy_power_lock_state_change_callback_handler(void *data)
685 {
686         struct power_lock_state_change_callback_handler *callback_handler =
687                 (struct power_lock_state_change_callback_handler *)data;
688         free(callback_handler);
689 }
690
691 int device_power_get_lock_state(power_lock_e power_lock_type,
692         device_power_lock_state_e *power_lock_state)
693 {
694         int ret, reply;
695
696         if (!power_is_valid_power_lock_type(power_lock_type)) {
697                 _E("Undefined power lock type");
698                 return DEVICE_ERROR_INVALID_PARAMETER;
699         }
700
701         if (!power_lock_state) {
702                 _E("Invalid parameters");
703                 return DEVICE_ERROR_INVALID_PARAMETER;
704         }
705
706         ret = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
707                                 DEVICED_PATH_DISPLAY,
708                                 DEVICED_INTERFACE_DISPLAY,
709                                 "PmlockGetLockState",
710                                 g_variant_new("(i)", (int)power_lock_type),
711                                 &reply);
712         if (ret < 0) {
713                 _E("Failed to call dbus method to get power lock state, return value(%d)", ret);
714                 return errno_to_device_error(ret);
715         }
716
717         *power_lock_state = (bool)reply;
718
719         return DEVICE_ERROR_NONE;
720 }
721
722 int device_power_get_lock_count(power_lock_e power_lock_type,
723         int *power_lock_count)
724 {
725         int ret, reply;
726
727         if (!power_is_valid_power_lock_type(power_lock_type)) {
728                 _E("Undefined power lock type");
729                 return DEVICE_ERROR_INVALID_PARAMETER;
730         }
731
732         if (!power_lock_count) {
733                 _E("Invalid parameters");
734                 return DEVICE_ERROR_INVALID_PARAMETER;
735         }
736
737         ret = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
738                                 DEVICED_PATH_DISPLAY,
739                                 DEVICED_INTERFACE_DISPLAY,
740                                 "PmlockGetLockCount",
741                                 g_variant_new("(i)", (int)power_lock_type),
742                                 &reply);
743         if (ret < 0) {
744                 _E("Failed to call dbus method to get power lock count, return value(%d)", ret);
745                 return errno_to_device_error(ret);
746         }
747
748         *power_lock_count = reply;
749
750         return DEVICE_ERROR_NONE;
751 }
752
753 int device_power_add_lock_state_change_callback(power_lock_e power_lock_type,
754         device_power_lock_state_change_callback power_lock_state_change_callback,
755         void *user_data)
756 {
757         GError *err = NULL;
758         GDBusConnection *connection;
759         int signal_subscription_id = 0;
760
761         if (!power_is_valid_power_lock_type(power_lock_type)) {
762                 _E("Undefined power lock type");
763                 return DEVICE_ERROR_INVALID_PARAMETER;
764         }
765
766         if (!power_lock_state_change_callback) {
767                 _E("Invalid parameters");
768                 return DEVICE_ERROR_INVALID_PARAMETER;
769         }
770
771         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
772         if (!connection) {
773                 _E("Failed to get dbus connection, %s", err->message);
774                 g_clear_error(&err);
775                 return DEVICE_ERROR_OPERATION_FAILED;
776         }
777
778         struct power_lock_state_change_callback_handler *callback_handler;
779
780         callback_handler = malloc(sizeof(struct power_lock_state_change_callback_handler));
781         if (!callback_handler) {
782                 _E("Cannot alloc memory for power lock state change callback");
783                 return DEVICE_ERROR_OPERATION_FAILED;
784         }
785         callback_handler->callback = power_lock_state_change_callback;
786         callback_handler->data = user_data;
787
788         if (power_lock_state_callback_signal_subscription_id[power_lock_type] == 0) {
789                 signal_subscription_id = g_dbus_connection_signal_subscribe(connection,
790                         DEVICED_BUS_NAME,
791                         DEVICED_INTERFACE_DISPLAY,
792                         DEVICED_SIGNAL_POWER_LOCK_STATE_CHANGED,
793                         DEVICED_PATH_DISPLAY,
794                         NULL,
795                         G_DBUS_SIGNAL_FLAGS_NONE,
796                         power_lock_state_change_cb,
797                         NULL,
798                         destroy_power_lock_state_change_callback_handler);
799                 power_lock_state_callback_signal_subscription_id[power_lock_type] =
800                         signal_subscription_id;
801         }
802
803         power_lock_state_callback_list[power_lock_type] =
804                 g_list_append(power_lock_state_callback_list[power_lock_type], callback_handler);
805
806         return DEVICE_ERROR_NONE;
807 }
808
809 int device_power_remove_lock_state_change_callback(power_lock_e power_lock_type,
810         device_power_lock_state_change_callback power_lock_state_change_callback)
811 {
812         struct power_lock_state_change_callback_handler *callback_handler;
813         GList **callback_list;
814         GList *elem, *elem_next;
815         GError *err = NULL;
816         GDBusConnection *connection;
817
818         if (!power_is_valid_power_lock_type(power_lock_type)) {
819                 _E("Undefined power lock type");
820                 return DEVICE_ERROR_INVALID_PARAMETER;
821         }
822
823         if (!power_lock_state_change_callback) {
824                 _E("Invalid parameters");
825                 return DEVICE_ERROR_INVALID_PARAMETER;
826         }
827
828         callback_list = &power_lock_state_callback_list[power_lock_type];
829         if (g_list_length(*callback_list) <= 0) {
830                 _W("No callback functions for power_lock_type(%d)", power_lock_type);
831                 return DEVICE_ERROR_NONE;
832         }
833
834         SYS_G_LIST_FOREACH_SAFE(*callback_list, elem, elem_next, callback_handler) {
835                 if (callback_handler->callback == power_lock_state_change_callback)
836                         break;
837         }
838
839         SYS_G_LIST_REMOVE(*callback_list, callback_handler);
840         free(callback_handler);
841
842         if (SYS_G_LIST_LENGTH(*callback_list) == 0) {
843                 connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
844                 if (!connection) {
845                         _E("Failed to get dbus connection, %s", err->message);
846                         g_clear_error(&err);
847                         return DEVICE_ERROR_OPERATION_FAILED;
848                 }
849                 g_dbus_connection_signal_unsubscribe(connection,
850                         power_lock_state_callback_signal_subscription_id[power_lock_type]);
851                 power_lock_state_callback_signal_subscription_id[power_lock_type] = 0;
852         }
853
854         return DEVICE_ERROR_NONE;
855 }
856
857 int device_power_add_lock_count_change_callback(power_lock_e power_lock_type,
858         device_power_lock_count_change_callback power_lock_count_change_callback,
859         void *user_data)
860 {
861         GError *err = NULL;
862         GDBusConnection *connection;
863         int signal_subscription_id = 0;
864
865         if (!power_is_valid_power_lock_type(power_lock_type)) {
866                 _E("Undefined power lock type");
867                 return DEVICE_ERROR_INVALID_PARAMETER;
868         }
869
870         if (!power_lock_count_change_callback) {
871                 _E("Invalid parameters");
872                 return DEVICE_ERROR_INVALID_PARAMETER;
873         }
874
875         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
876         if (!connection) {
877                 _E("Failed to get dbus connection, %s", err->message);
878                 g_clear_error(&err);
879                 return DEVICE_ERROR_OPERATION_FAILED;
880         }
881
882         struct power_lock_count_change_callback_handler *callback_handler;
883
884         callback_handler = malloc(sizeof(struct power_lock_count_change_callback_handler));
885         if (!callback_handler) {
886                 _E("Cannot alloc memory for power lock count change callback");
887                 return DEVICE_ERROR_OPERATION_FAILED;
888         }
889         callback_handler->callback = power_lock_count_change_callback;
890         callback_handler->data = user_data;
891
892         if (power_lock_count_callback_signal_subscription_id[power_lock_type] == 0) {
893                 signal_subscription_id = g_dbus_connection_signal_subscribe(connection,
894                         DEVICED_BUS_NAME,
895                         DEVICED_INTERFACE_DISPLAY,
896                         DEVICED_SIGNAL_POWER_LOCK_COUNT_CHANGED,
897                         DEVICED_PATH_DISPLAY,
898                         NULL,
899                         G_DBUS_SIGNAL_FLAGS_NONE,
900                         power_lock_count_change_cb,
901                         NULL,
902                         NULL);
903                 power_lock_count_callback_signal_subscription_id[power_lock_type] =
904                         signal_subscription_id;
905         }
906
907         power_lock_count_callback_list[power_lock_type] =
908                 g_list_append(power_lock_count_callback_list[power_lock_type], callback_handler);
909
910         return DEVICE_ERROR_NONE;
911 }
912
913 int device_power_remove_lock_count_change_callback(power_lock_e power_lock_type,
914         device_power_lock_count_change_callback power_lock_count_change_callback)
915 {
916         struct power_lock_count_change_callback_handler *callback_handler;
917         GList **callback_list;
918         GList *elem, *elem_next;
919         GError *err = NULL;
920         GDBusConnection *connection;
921
922         if (!power_is_valid_power_lock_type(power_lock_type)) {
923                 _E("Undefined power lock type");
924                 return DEVICE_ERROR_INVALID_PARAMETER;
925         }
926
927         if (!power_lock_count_change_callback) {
928                 _E("Invalid parameters");
929                 return DEVICE_ERROR_INVALID_PARAMETER;
930         }
931
932         callback_list = &power_lock_count_callback_list[power_lock_type];
933         if (g_list_length(*callback_list) <= 0) {
934                 _W("No callback functions for power_lock_type(%d)", power_lock_type);
935                 return DEVICE_ERROR_NONE;
936         }
937
938         SYS_G_LIST_FOREACH_SAFE(*callback_list, elem, elem_next, callback_handler) {
939                 if (callback_handler->callback == power_lock_count_change_callback)
940                         break;
941         }
942
943         SYS_G_LIST_REMOVE(*callback_list, callback_handler);
944         free(callback_handler);
945
946         if (SYS_G_LIST_LENGTH(*callback_list) == 0) {
947                 connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
948                 if (!connection) {
949                         _E("Failed to get dbus connection, %s", err->message);
950                         g_clear_error(&err);
951                         return DEVICE_ERROR_OPERATION_FAILED;
952                 }
953                 g_dbus_connection_signal_unsubscribe(connection,
954                         power_lock_count_callback_signal_subscription_id[power_lock_type]);
955                 power_lock_count_callback_signal_subscription_id[power_lock_type] = 0;
956         }
957
958         return DEVICE_ERROR_NONE;
959 }
960 //LCOV_EXCL_STOP