power: elevate iot-headless power plugin to core
[platform/core/system/deviced.git] / src / power / power-state-wait.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2022 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 #include <unistd.h>
20 #include <stdint.h>
21 #include <inttypes.h>
22 #include <libsyscommon/list.h>
23 #include <device/power-internal.h>
24
25 #include "shared/log.h"
26 #include "shared/device-notifier.h"
27 #include "shared/common.h"
28
29 #include "power-state-wait.h"
30 #include "power-state-manager.h"
31
32 #define POWER_CONF_FILE    "/etc/deviced/power.conf"
33 #define MAX_WAIT_SECOND    5 /* second */
34
35 static int max_wait_timeout = 5; /* second */
36
37 struct proc_info {
38         pid_t pid;
39         char comm[128];
40         guint64 state_bitmap;
41         int killed;
42 };
43
44 struct change_state_wait {
45         struct proc_info *pi;
46         guint64 id;
47         enum psm_state state;
48 };
49
50 static GList *proc_list;
51 static GList *waiting_list;
52 static int max_wait_timer;
53 static void (*__change_state_wait_done) (void);
54 static enum psm_state waiting_state;
55
56 static void change_state_wait_done(void)
57 {
58         _D("%s wait done", psm_name[waiting_state]);
59
60         if (max_wait_timer) {
61                 g_source_remove(max_wait_timer);
62                 max_wait_timer = 0;
63         }
64
65         if (__change_state_wait_done) {
66                 __change_state_wait_done();
67         }
68 }
69
70 static gboolean max_wait_expired_cb(void *data)
71 {
72         struct change_state_wait *csw;
73         struct proc_info *pi;
74         GList *elem, *elem_next;
75
76         max_wait_timer = 0;
77
78         SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) {
79                 if (kill(csw->pi->pid, 0) != 0)
80                         csw->pi->killed = 1;
81                 else
82                         _E("pid=%d(%s) hasn't confirmed id=%"PRIu64"(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]);
83                 waiting_list = g_list_remove_link(waiting_list, elem);
84                 g_list_free(elem);
85                 free(csw);
86         }
87
88         SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) {
89                 if (pi->killed) {
90                         _D("Clean up not existing pid=%d(%s)", pi->pid, pi->comm);
91                         proc_list = g_list_remove_link(proc_list, elem);
92                         g_list_free(elem);
93                         free(pi);
94                 }
95         }
96
97         change_state_wait_done();
98
99         return G_SOURCE_REMOVE;
100 }
101
102 int add_change_state_wait(pid_t pid, guint64 state)
103 {
104         struct proc_info *pi;
105         GList *elem;
106
107         SYS_G_LIST_FOREACH(proc_list, elem, pi) {
108                 if (pi->pid == pid) {
109                         pi->state_bitmap |= state;
110                         _D("pid=%d(%s) updated csw for %#"PRIx64, pid, pi->comm, state);
111                         return 0;
112                 }
113         }
114
115         pi = calloc(1, sizeof(struct proc_info));
116         if (!pi)
117                 return -ENOMEM;
118
119         pi->pid = pid;
120         pi->state_bitmap = state;
121         get_command(pid, pi->comm, sizeof(pi->comm));
122         SYS_G_LIST_APPEND(proc_list, pi);
123
124         _D("pid=%d(%s) added csw for %#"PRIx64, pid, pi->comm, state);
125
126         return 0;
127 }
128
129 void remove_change_state_wait(pid_t pid, guint64 state)
130 {
131         struct proc_info *pi;
132         GList *elem, *elem_next;
133
134         _D("pid=%d removed csw for %#"PRIx64, pid, state);
135
136         SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) {
137                 if (pi->pid == pid) {
138                         pi->state_bitmap &= ~state;
139                         if (pi->state_bitmap == 0) {
140                                 proc_list = g_list_remove_link(proc_list, elem);
141                                 g_list_free(elem);
142                                 free(pi);
143                         }
144                 }
145         }
146 }
147
148 int confirm_change_state_wait(pid_t pid, guint64 id)
149 {
150         struct change_state_wait *csw;
151         GList *elem, *elem_next;
152
153         SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) {
154                 if (csw->pi->pid == pid && csw->id == id) {
155                         _D("pid=%d(%s) confirmed id=%"PRIu64"(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]);
156                         waiting_list = g_list_remove_link(waiting_list, elem);
157                         g_list_free(elem);
158                         free(csw);
159
160                         if (SYS_G_LIST_LENGTH(waiting_list) == 0) {
161                                 change_state_wait_done();
162                                 return 0;
163                         }
164                 }
165         }
166
167         return 0;
168 }
169
170 static int check_proc_requested_wait_for_state(struct proc_info *pi, enum psm_state state)
171 {
172         if (!pi)
173                 return 0;
174
175         if (state == PSM_NORMAL)
176                 return (pi->state_bitmap & POWER_STATE_NORMAL);
177         if (state == PSM_SLEEP)
178                 return (pi->state_bitmap & POWER_STATE_SLEEP);
179         if (state == PSM_POWEROFF)
180                 return (pi->state_bitmap & POWER_STATE_POWEROFF);
181         if (state == PSM_REBOOT)
182                 return (pi->state_bitmap & POWER_STATE_REBOOT);
183
184         return 0;
185 }
186
187 int update_change_state_wait(guint64 id, const struct trans_info *ti, change_state_wait_done_cb callback)
188 {
189         struct proc_info *pi;
190         struct change_state_wait *csw;
191         GList *elem, *elem_next;
192         int n_waiting;
193
194         // initialize timer
195         if (max_wait_timer) {
196                 g_source_remove(max_wait_timer);
197                 max_wait_timer = 0;
198         }
199
200         // we are waiting for confirm of transition to the next state
201         waiting_state = ti->next;
202         _D("%s wait is triggered, id=%"PRIu64, psm_name[waiting_state], id);
203
204         // cancel all ongoing csw that is not a waiting for the next state
205         SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) {
206                 if (csw->state != waiting_state) {
207                         waiting_list = g_list_remove_link(waiting_list, elem);
208                         g_list_free(elem);
209                         _D("Cancel waiting: pid=%d(%s) for id=%"PRIu64"(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]);
210                         free(csw);
211                 }
212         }
213
214         // add wait list
215         SYS_G_LIST_FOREACH(proc_list, elem, pi) {
216                 if (check_proc_requested_wait_for_state(pi, waiting_state)) {
217                         csw = calloc(1, sizeof(struct change_state_wait));
218                                 if (!csw)
219                                         continue;
220
221                         csw->pi = pi;
222                         csw->id = id;
223                         csw->state = waiting_state;
224                         SYS_G_LIST_APPEND(waiting_list, csw);
225                 }
226         }
227
228         n_waiting = SYS_G_LIST_LENGTH(waiting_list);
229         if (n_waiting == 0) {
230                 _D("There were no csw requests for %s, skip waiting", psm_name[waiting_state]);
231                 __change_state_wait_done = NULL;
232                 return 0;
233         }
234
235         __change_state_wait_done = callback;
236
237         _D("The number of pending wait confirm=%d", n_waiting);
238         max_wait_timer = g_timeout_add_seconds(max_wait_timeout, max_wait_expired_cb, NULL);
239
240         return n_waiting;
241 }
242
243 static int load_max_wait_timeout(struct parse_result *result, void *user_data)
244 {
245         if (MATCH(result->section, "PowerState")
246                 && MATCH(result->name, "ChangeStateMaxWaitSecond"))
247                 max_wait_timeout = atoi(result->value);
248
249         return 0;
250 }
251
252 void power_state_wait_init(void)
253 {
254         config_parse(POWER_CONF_FILE, load_max_wait_timeout, NULL);
255
256         CRITICAL_LOG("Change state max wait timeout=%ds", max_wait_timeout);
257 }