2 * Copyright (c) 2011 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <libsyscommon/libgdbus.h>
27 #include <libsyscommon/ini-parser.h>
30 #include "power-internal.h"
32 #include "display-internal.h"
36 * Parameters for device_power_request_lock()
38 #define STAY_CUR_STATE 0x1
39 #define GOTO_STATE_NOW 0x2
40 #define HOLD_KEY_BLOCK 0x4
41 #define STANDBY_MODE 0x8
44 * Parameters for device_power_request_unlock()
46 #define PM_SLEEP_MARGIN 0x0 /**< keep guard time for unlock */
47 #define PM_RESET_TIMER 0x1 /**< reset timer for unlock */
48 #define PM_KEEP_TIMER 0x2 /**< keep timer for unlock */
50 #define METHOD_LOCK_STATE "lockstate"
51 #define METHOD_UNLOCK_STATE "unlockstate"
52 #define METHOD_CHANGE_STATE "changestate"
53 #define METHOD_POWEROFF "PowerOff"
54 #define METHOD_POWEROFF_WITH_OPTION "PowerOffWithOption"
56 #define TYPE_POWEROFF "poweroff"
57 #define TYPE_REBOOT "reboot"
58 #define REBOOT_REASON_NONE ""
60 #define STR_STAYCURSTATE "staycurstate"
61 #define STR_GOTOSTATENOW "gotostatenow"
63 #define STR_HOLDKEYBLOCK "holdkeyblock"
64 #define STR_STANDBYMODE "standbymode"
65 #define STR_NULL "NULL"
67 #define STR_SLEEP_MARGIN "sleepmargin"
68 #define STR_RESET_TIMER "resettimer"
69 #define STR_KEEP_TIMER "keeptimer"
71 #define STR_LCD_OFF "lcdoff"
72 #define STR_LCD_DIM "lcddim"
73 #define STR_LCD_ON "lcdon"
75 #define LOCK_CPU_TIMEOUT_MAX (24*60*60*1000) /* milliseconds */
76 #define LOCK_CPU_PADDING_TIMEOUT (20*1000) /* milliseconds */
78 #define POWER_CONF "/etc/deviced/device/power.conf"
80 static guint off_lock_timeout;
81 static guint padding_timeout;
82 static int prev_count;
84 static GList *request_id_list;
86 static struct _lock_timeout {
90 .release = LOCK_CPU_TIMEOUT_MAX,
91 .padding = LOCK_CPU_PADDING_TIMEOUT,
93 static bool power_locked_CPU;
94 static bool power_locked_DISPLAY;
95 static bool power_locked_DISPLAY_DIM;
97 static char *get_state_str(display_state_e state)
100 case DISPLAY_STATE_NORMAL:
102 case DISPLAY_STATE_SCREEN_DIM:
104 case DISPLAY_STATE_SCREEN_OFF:
112 static void remove_off_lock_timeout(void)
114 if (!TIZEN_FEATURE_TRACKER)
116 if (off_lock_timeout) {
117 _I("Power lock timeout handler removed"); //LCOV_EXCL_LINE Logs
118 g_source_remove(off_lock_timeout);
119 off_lock_timeout = 0;
123 static void remove_padding_timeout(void)
125 if (!TIZEN_FEATURE_TRACKER)
127 if (padding_timeout) {
128 _I("Padding timeout handler removed"); //LCOV_EXCL_LINE Logs
129 g_source_remove(padding_timeout);
134 //LCOV_EXCL_START Callback function
135 static void notice_lock_expired_done(GVariant *result, void *data, GError *err)
145 g_variant_get(result, "(&si)", &id, &val);
148 len = strlen(id) + 1;
149 for (l = request_id_list, l_next = g_list_next(l);
150 l && (elem = l->data) != NULL;
151 l = l_next, l_next = g_list_next(l), elem = NULL) {
152 if (!strncmp(id, elem, len))
158 request_id_list = g_list_remove(request_id_list, elem);
161 if (val == 0) { /* Allow to lock cpu */
162 _I("Continue Power Lock");
164 } else if (val == 1) { /* Release cpu lock */
165 ret_val = device_power_release_lock(POWER_LOCK_CPU);
166 if (ret_val != DEVICE_ERROR_NONE)
167 _E("Failed to release power(CPU) (%d)", ret_val);
172 //LCOV_EXCL_START Callback function
173 static char *get_new_request_id(pid_t pid)
176 snprintf(id, sizeof(id), "%d_%lu", pid, time(NULL));
181 //LCOV_EXCL_START Callback function
182 static int notice_power_lock_expired(void)
190 req_id = get_new_request_id(pid);
192 _E("Failed to get request id");
196 ret_dbus = gdbus_call_async_with_reply(
198 DEVICED_PATH_DISPLAY,
199 DEVICED_INTERFACE_DISPLAY,
200 "LockTimeoutExpired",
201 g_variant_new("(s)", req_id),
202 notice_lock_expired_done,
206 _E("Failed to notice power lock expired (%d)", ret_dbus);
211 request_id_list = g_list_append(request_id_list, req_id);
212 _I("request ID %s is added", req_id);
218 //LCOV_EXCL_START Callback function
219 static gboolean padding_timeout_expired(gpointer data)
224 _I("Padding timeout expired");
226 remove_padding_timeout();
228 ret_val = tracker_get_ref_counter(TRACKER_TYPE_POWER_LOCK, &ref);
229 if (ret_val != TRACKER_ERROR_NONE) {
230 _E("Failed to get reference count of power lock");
234 _I("reference count of power lock is (%d)", ref);
236 _I("Power Lock continue (Reference count > 0 !!)");
237 return G_SOURCE_REMOVE;
240 ret_val = tracker_get_tick(TRACKER_TYPE_POWER_LOCK, &count);
241 if (ret_val != TRACKER_ERROR_NONE) {
242 _E("Failed to get total count of power lock(%d)", ret_val);
246 if (count != prev_count) {
247 _I("Power Lock continue (Total reference count increased !!)");
248 return G_SOURCE_REMOVE;
252 ret_val = notice_power_lock_expired();
254 _E("Failed to launch power lock expired popup (%d)", ret_val);
255 return G_SOURCE_CONTINUE;
258 remove_off_lock_timeout();
260 return G_SOURCE_REMOVE;
264 //LCOV_EXCL_START Callback function
265 static void add_padding_timeout(void)
269 remove_padding_timeout();
271 _I("Padding timeout handler added");
273 id = g_timeout_add(lock_timeout.padding,
274 padding_timeout_expired, NULL);
276 padding_timeout = id;
278 _E("Failed to add timeout for padding time");
282 //LCOV_EXCL_START Callback function
283 static gboolean off_lock_timeout_expired(gpointer data)
287 _I("Power lock timeout expired");
289 ret_val = tracker_get_ref_counter(TRACKER_TYPE_POWER_LOCK, &ref);
290 if (ret_val != TRACKER_ERROR_NONE) {
291 _E("Failed to get reference count of power lock(%d)", ret_val);
292 remove_off_lock_timeout();
293 return G_SOURCE_REMOVE;
296 _I("reference count of power lock is (%d)", ref);
300 add_padding_timeout();
302 ret_val = tracker_get_tick(TRACKER_TYPE_POWER_LOCK, &prev_count);
303 if (ret_val != TRACKER_ERROR_NONE)
304 _E("Failed to get total count of power lock(%d)", ret_val);
307 return G_SOURCE_CONTINUE;
311 static void add_off_lock_timeout(void)
315 if (!TIZEN_FEATURE_TRACKER)
318 remove_off_lock_timeout();
319 remove_padding_timeout();
321 _I("Power lock timeout handler added"); //LCOV_EXCL_LINE Logs
323 id = g_timeout_add(lock_timeout.release,
324 off_lock_timeout_expired, NULL);
326 off_lock_timeout = id;
328 _E("Failed to add Power Lock timeout handler"); //LCOV_EXCL_LINE Logs
331 static void lock_cb(GVariant *result, void *data, GError *err)
336 //LCOV_EXCL_START System Error
337 _E("no message : %s", err->message);
342 g_variant_get(result, "(i)", &ret_val);
343 _D("%s-%s : %d", DEVICED_INTERFACE_DISPLAY, METHOD_LOCK_STATE, ret_val);
346 remove_off_lock_timeout();
349 static int lock_state(display_state_e state, unsigned int flag, int timeout_ms)
353 static int privilege = -1;
355 if (flag & GOTO_STATE_NOW)
356 arr[1] = STR_GOTOSTATENOW;
358 arr[1] = STR_STAYCURSTATE;
360 if (flag & HOLD_KEY_BLOCK)
361 arr[2] = STR_HOLDKEYBLOCK;
362 else if (flag & STANDBY_MODE)
363 arr[2] = STR_STANDBYMODE;
368 arr[0] = "privilege check";
370 ret_dbus = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
371 DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
372 METHOD_LOCK_STATE, g_variant_new("(sssi)", arr[0], arr[1], arr[2], timeout_ms),
374 //LCOV_EXCL_START System Error
382 arr[0] = get_state_str(state);
386 return gdbus_call_async_with_reply(DEVICED_BUS_NAME,
387 DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
388 METHOD_LOCK_STATE, g_variant_new("(sssi)", arr[0], arr[1], arr[2], timeout_ms), lock_cb, -1, NULL);
391 static void unlock_cb(GVariant *result, void *data, GError *err)
396 //LCOV_EXCL_START System Error
397 _E("no message : %s", err->message);
402 g_variant_get(result, "(i)", &ret_val);
403 _D("%s-%s : %d", DEVICED_INTERFACE_DISPLAY, METHOD_UNLOCK_STATE, ret_val);
406 static int unlock_state(display_state_e state, unsigned int flag)
410 static int privilege = -1;
412 if (flag == PM_SLEEP_MARGIN)
413 arr[1] = STR_SLEEP_MARGIN;
414 else if (flag == PM_RESET_TIMER)
415 arr[1] = STR_RESET_TIMER;
416 else if (flag == PM_KEEP_TIMER)
417 arr[1] = STR_KEEP_TIMER;
422 arr[0] = "privilege check";
424 ret_dbus = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
425 DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
426 METHOD_UNLOCK_STATE, g_variant_new("(ss)", arr[0], arr[1]),
428 //LCOV_EXCL_START System Error
436 arr[0] = get_state_str(state);
440 return gdbus_call_async_with_reply(DEVICED_BUS_NAME,
441 DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
442 METHOD_UNLOCK_STATE, g_variant_new("(ss)", arr[0], arr[1]), unlock_cb, -1, NULL);
445 int device_power_request_lock(power_lock_e type, int timeout_ms)
448 static long num_calls = 0;
450 _I("power_lock_e = %d", type);
452 if (!is_feature_display_supported() || !is_feature_display_state_supported()) {
453 if ((type == POWER_LOCK_DISPLAY) || (type == POWER_LOCK_DISPLAY_DIM)) {
454 return DEVICE_ERROR_NOT_SUPPORTED;
455 } else if (type == POWER_LOCK_CPU) {
456 /* in case of headless, request for cpu lock is handled
457 * in power module of deviced, not in display module */
458 ret = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
459 DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER,
460 "LockCpu", g_variant_new("(i)", timeout_ms), NULL);
461 return errno_to_device_error(ret);
465 if (check_async_call_rate(&num_calls) < 0) {
466 //LCOV_EXCL_START System Error
467 _E("Rejected by too frequent calls; %d (calls per sec.) limit is violated."
468 , CHECK_RATE_THRESHOLD);
469 return DEVICE_ERROR_OPERATION_FAILED;
474 return DEVICE_ERROR_INVALID_PARAMETER;
476 if (type == POWER_LOCK_CPU) {
477 ret = lock_state(DISPLAY_STATE_SCREEN_OFF, STAY_CUR_STATE, timeout_ms);
479 (timeout_ms == 0 || timeout_ms > lock_timeout.release))
480 add_off_lock_timeout();
481 power_locked_CPU = true;
482 } else if (type == POWER_LOCK_DISPLAY) {
483 ret = lock_state(DISPLAY_STATE_NORMAL, STAY_CUR_STATE, timeout_ms);
484 power_locked_DISPLAY = true;
486 else if (type == POWER_LOCK_DISPLAY_DIM) {
487 ret = lock_state(DISPLAY_STATE_SCREEN_DIM, STAY_CUR_STATE, timeout_ms);
488 power_locked_DISPLAY_DIM = true;
491 return DEVICE_ERROR_INVALID_PARAMETER;
493 return errno_to_device_error(ret);
496 int device_power_release_lock(power_lock_e type)
500 _I("power_lock_e = %d", type);
502 if (!is_feature_display_supported() || !is_feature_display_state_supported()) {
503 if ((type == POWER_LOCK_DISPLAY) || (type == POWER_LOCK_DISPLAY_DIM)) {
504 return DEVICE_ERROR_NOT_SUPPORTED;
505 } else if (type == POWER_LOCK_CPU) {
506 /* in case of headless, request for cpu unlock is handled
507 * in power module of deviced, not in display module */
508 ret_val = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
509 DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER,
510 "UnlockCpu", NULL, NULL);
511 return errno_to_device_error(ret_val);
515 if (type == POWER_LOCK_CPU && power_locked_CPU) {
516 ret_val = unlock_state(DISPLAY_STATE_SCREEN_OFF, PM_SLEEP_MARGIN);
518 remove_off_lock_timeout();
519 remove_padding_timeout();
520 power_locked_CPU = false;
522 } else if (type == POWER_LOCK_DISPLAY && power_locked_DISPLAY) {
523 ret_val = unlock_state(DISPLAY_STATE_NORMAL, PM_KEEP_TIMER);
524 if (ret_val == 0) power_locked_DISPLAY = false;
526 else if (type == POWER_LOCK_DISPLAY_DIM && power_locked_DISPLAY_DIM) {
527 ret_val = unlock_state(DISPLAY_STATE_SCREEN_DIM, PM_KEEP_TIMER);
528 if (ret_val == 0) power_locked_DISPLAY_DIM = false;
531 return DEVICE_ERROR_INVALID_PARAMETER;
533 return errno_to_device_error(ret_val);
536 int device_power_wakeup(bool dim)
540 ret_val = is_feature_display_state_supported();
542 return DEVICE_ERROR_NOT_SUPPORTED;
545 return device_display_change_state(DISPLAY_STATE_SCREEN_DIM);
547 return device_display_change_state(DISPLAY_STATE_NORMAL);
550 //LCOV_EXCL_START Not available to test (Reboot during TCT)
551 int device_power_reboot(const char *reason)
558 method = METHOD_POWEROFF_WITH_OPTION;
559 param = g_variant_new("(ss)", TYPE_REBOOT, reason);
561 method = METHOD_POWEROFF;
562 param = g_variant_new("(s)", TYPE_REBOOT);
565 ret_dbus = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
566 DEVICED_PATH_POWEROFF,
567 DEVICED_INTERFACE_POWEROFF,
568 method, param, NULL);
569 return errno_to_device_error(ret_dbus);
573 //LCOV_EXCL_START Not available to test (Reboot during TCT)
574 int device_power_poweroff(void)
578 ret_dbus = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
579 DEVICED_PATH_POWEROFF, DEVICED_INTERFACE_POWEROFF,
580 METHOD_POWEROFF, g_variant_new("(s)", TYPE_POWEROFF),
583 return errno_to_device_error(ret_dbus);
587 static int power_load_config(struct parse_result *result, void *data)
594 if (strncmp(result->section, "Power", 6))
597 value = strtoul(result->value, NULL, 10);
601 if (!strncmp(result->name, "LockTimeout", 12)) {
602 _I("Power Lock Auto Release Timeout: %u msec", value);
603 lock_timeout.release = value;
604 } else if (!strncmp(result->name, "LockPaddingTimeout", 12)) {
605 _I("Power Lock Auto Release Padding Timeout: %u msec", value);
606 lock_timeout.padding = value;
612 static void __CONSTRUCTOR__ power_init(void)
616 ret_val = config_parse(POWER_CONF, power_load_config, NULL);
618 _E("Failed to load config file (%d)", ret_val); //LCOV_EXCL_LINE Logs