power: refactor power operations
[platform/core/system/deviced.git] / src / power / power-suspend.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <limits.h>
29 #include <math.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <dlfcn.h>
33 #include <libsyscommon/libgdbus.h>
34 #include <libsyscommon/ini-parser.h>
35
36 #include "core/log.h"
37 #include "shared/devices.h"
38 #include "shared/common.h"
39 #include "shared/device-notifier.h"
40 #include "vconf.h"
41 #include "display/display-dpms.h"
42 #include "display/display.h"
43 #include "power-boot.h"
44 #include "power-suspend.h"
45
46 #define POWER_CONF_FILE             "/etc/deviced/power.conf"
47
48 static int mainlock_status = POWER_UNLOCK;
49 static int vital_service;
50 static bool vital_sleep;
51 static int vital_support = -2;
52
53 #ifdef ENABLE_PM_LOG
54
55 typedef struct _pm_history {
56         time_t time;
57         enum pm_log_type log_type;
58         int keycode;
59 } pm_history;
60
61 static int max_history_count = MAX_LOG_COUNT;
62 static pm_history pm_history_log[MAX_LOG_COUNT] = {{0, }, };
63 static int history_count = 0;
64
65 static const char history_string[PM_LOG_MAX][15] = {
66         "PRESS", "LONG PRESS", "RELEASE", "LCD ON", "LCD ON COMPL", "LCD ON FAIL",
67         "LCD DIM", "LCD DIM FAIL", "LCD OFF", "LCD OFF COMPL", "LCD OFF FAIL",
68         "LCD FAIL", "SLEEP"};
69
70 bool timeout_sleep_support = false;
71
72 void pm_history_init()
73 {
74         memset(pm_history_log, 0x0, sizeof(pm_history_log));
75         history_count = 0;
76         max_history_count = MAX_LOG_COUNT;
77 }
78
79 void pm_history_save(enum pm_log_type log_type, int code)
80 {
81         time_t now;
82
83         time(&now);
84         pm_history_log[history_count].time = now;
85         pm_history_log[history_count].log_type = log_type;
86         pm_history_log[history_count].keycode = code;
87         history_count++;
88
89         if (history_count >= max_history_count)
90                 history_count = 0;
91 }
92
93 void pm_history_print(int fd, int count)
94 {
95         int start_index, index, i;
96         int ret_val;
97         char buf[255];
98         char time_buf[30];
99
100         if (count <= 0 || count > max_history_count)
101                 return;
102
103         start_index = (history_count - count + max_history_count)
104                     % max_history_count;
105
106         for (i = 0; i < count; i++) {
107                 index = (start_index + i) % max_history_count;
108
109                 if (pm_history_log[index].time == 0)
110                         continue;
111
112                 if (pm_history_log[index].log_type >= PM_LOG_MAX)
113                         continue;
114                 ctime_r(&pm_history_log[index].time, time_buf);
115                 time_buf[strlen(time_buf) - 1] = 0;
116                 snprintf(buf, sizeof(buf), "[%3d] %15s %3d %s\n",
117                         index,
118                         history_string[pm_history_log[index].log_type],
119                         pm_history_log[index].keycode,
120                         time_buf);
121                 ret_val = write(fd, buf, strlen(buf));
122                 if (ret_val < 0)
123                         _E("Write() failed: %d", errno);
124         }
125 }
126 #endif
127
128 bool vital_mode(void)
129 {
130         return vital_sleep;
131 }
132
133 static int vital_mode_support(void)
134 {
135         if (vital_support < 0) {
136                 FILE *fp;
137
138                 fp = fopen(FREEZER_VITAL_WAKEUP_CGROUP, "r");
139                 if (fp == NULL) {
140                         _E("%s open failed", FREEZER_VITAL_WAKEUP_CGROUP);
141                         /* read max 2 times to check if this file exist */
142                         vital_support++;
143                         return 0;
144                 }
145                 vital_support = 1;
146                 fclose(fp);
147         }
148         return vital_support;
149 }
150
151 int suspend_other_process(int type)
152 {
153         int ret = 0;
154
155         if (vital_service == type)
156                 return ret;
157
158         if (type == VITAL_WAKEUP && vital_service > VITAL_SLEEP)
159                 return ret;
160
161         vital_service = type;
162
163         if (!vital_mode_support())
164                 return ret;
165
166         if (type == VITAL_SLEEP) {
167                 gdbus_call_sync_with_reply_timeout(RESOURCED_BUS_NAME,
168                                                 RESOURCED_PATH_FREEZER,
169                                                 RESOURCED_INTERFACE_FREEZER,
170                                                 "SetSuspend",
171                                                 g_variant_new("(s)", "sleep"),
172                                                 NULL,
173                                                 SET_SUSPEND_TIME*1000);
174                 vital_sleep = true;
175         } else if (type == VITAL_WAKEUP) {
176                 ret = gdbus_call_async(RESOURCED_BUS_NAME,
177                                                 RESOURCED_PATH_FREEZER,
178                                                 RESOURCED_INTERFACE_FREEZER,
179                                                 "SetSuspend",
180                                                 g_variant_new("(s)", "wakeup"));
181         } else if (type == VITAL_EXIT) {
182                 ret = gdbus_call_async(RESOURCED_BUS_NAME,
183                                                 RESOURCED_PATH_FREEZER,
184                                                 RESOURCED_INTERFACE_FREEZER,
185                                                 "SetSuspend",
186                                                 g_variant_new("(s)", "exit"));
187                 vital_sleep = false;
188         }
189         return ret;
190 }
191
192 int vital_state_changed(void *data)
193 {
194         int type;
195
196         assert(data);
197
198         type = *(int *)data;
199         if (type == VITAL_EXIT)
200                 suspend_other_process(VITAL_EXIT);
201
202         return 0;
203 }
204
205 int pm_suspend(void)
206 {
207         int ret_val;
208
209         _I("system suspend");
210         ret_val = sys_set_str(POWER_STATE_PATH, "mem");
211         _I("System resume: %d", ret_val);
212         return 0;
213 }
214
215 int power_enable_autosleep(void)
216 {
217         _I("System autosleep enabled.");
218         return sys_set_str(POWER_AUTOSLEEP_PATH, "mem");
219 }
220
221 int power_disable_autosleep(void)
222 {
223         _I("System autosleep disabled.");
224         return sys_set_str(POWER_AUTOSLEEP_PATH, "off");
225 }
226
227 int power_acquire_wakelock(void)
228 {
229         if (mainlock_status == POWER_LOCK)
230                 return 0;
231
232         _I("system power lock");
233         suspend_other_process(VITAL_WAKEUP);
234         mainlock_status = POWER_LOCK;
235
236         return sys_set_str(POWER_LOCK_PATH, "mainlock");
237 }
238
239 int pm_get_power_lock(void)
240 {
241         return mainlock_status;
242 }
243
244 int pm_get_power_lock_support(void)
245 {
246         static int power_lock_support = -1;
247         int ret_val;
248
249         if (power_lock_support >= 0)
250                 goto out;
251
252         ret_val = sys_check_node(POWER_LOCK_PATH);
253         if (ret_val < 0)
254                 power_lock_support = false;
255         else
256                 power_lock_support = true;
257
258         _I("System power lock: %s",
259                         (power_lock_support ? "support" : "not support"));
260
261 out:
262         return power_lock_support;
263 }
264
265 int power_release_wakelock(void)
266 {
267         if (mainlock_status == POWER_UNLOCK)
268                 return 0;
269
270         _I("system power unlock");
271         suspend_other_process(VITAL_SLEEP);
272         mainlock_status = POWER_UNLOCK;
273
274         return sys_set_str(POWER_UNLOCK_PATH, "mainlock");
275 }
276
277 int check_wakeup_src(void)
278 {
279         /*  TODO if nedded.
280          * return wackeup source. user input or device interrupts? (EVENT_DEVICE or EVENT_INPUT)
281          */
282         return EVENT_DEVICE;
283 }
284
285 int get_wakeup_count(int *cnt)
286 {
287         int ret_val;
288         int wakeup_count;
289
290         if (!cnt)
291                 return -EINVAL;
292
293         ret_val = sys_get_int(POWER_WAKEUP_PATH, &wakeup_count);
294         if (ret_val < 0)
295                 return ret_val;
296
297         *cnt = wakeup_count;
298         return 0;
299 }
300
301 int set_wakeup_count(int cnt)
302 {
303         int ret_val;
304
305         ret_val = sys_set_int(POWER_WAKEUP_PATH, cnt);
306         if (ret_val < 0)
307                 return ret_val;
308
309         return 0;
310 }
311
312 static int load_sleep_config(struct parse_result *result, void *user_data)
313 {
314         if (!MATCH(result->section, "PowerState"))
315                 return 0;
316
317         if (MATCH(result->name, "TimeoutSleepSupport") && MATCH(result->value, "yes")) {
318                 timeout_sleep_support = true;
319                 _D("timeout_sleep_support=%d", timeout_sleep_support);
320         }
321
322         return 0;
323 }
324
325 void power_suspend_init(void)
326 {
327         int retval;
328
329         retval = config_parse(POWER_CONF_FILE, load_sleep_config, NULL);
330         if (retval < 0)
331                 _E("Failed to load sleep config: %d", retval);
332 }