power: elevate iot-headless power plugin to core
[platform/core/system/deviced.git] / src / power / power-boot.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2016 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 <stdio.h>
20 #include <unistd.h>
21 #include <bundle.h>
22 #include <eventsystem.h>
23 #include <libsyscommon/libgdbus.h>
24 #include <libsyscommon/libsystemd.h>
25 #include <libsyscommon/list.h>
26 #include <libsyscommon/file.h>
27 #include <libsyscommon/ini-parser.h>
28 #include <hal/device/hal-board.h>
29
30 #include "core/log.h"
31 #include "shared/device-notifier.h"
32 #include "shared/common.h"
33 #include "display/poll.h"
34 #include "display/display-ops.h"
35 #include "shared/plugin.h"
36 #include "power-doze.h"
37 #include "power-state-manager.h"
38
39 #define SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED     "StartupFinished"
40 #define SYSTEMD_DBUS_SIGNAL_USER_STARTUP_FINISHED       "UserSessionStartupFinished"
41
42 #define INIT_CONF_PATH    "/etc/deviced/init.conf"
43
44 static struct trans_info initial_transition_info = {
45         .reason = -1,
46         .curr = PSM_START,
47         .next = PSM_NORMAL,
48 };
49
50 static guint sig_id[2] = {0, 0};
51
52 void remove_delayed_init_done_handler(void *data)
53 {
54         gdbus_signal_unsubscribe(NULL, sig_id[0]);
55         gdbus_signal_unsubscribe(NULL, sig_id[1]);
56 }
57
58 static void delayed_init_done_received(GDBusConnection  *conn,
59         const gchar      *sender,
60         const gchar      *path,
61         const gchar      *iface,
62         const gchar      *name,
63         GVariant         *param,
64         gpointer          data)
65 {
66         static int system_done = 0;
67         static int user_done = 0;
68
69         if (strcmp(name, SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED) == 0) {
70                 if (system_done)
71                         return;
72
73                 system_done = check_system_boot_finished();
74                 if (system_done == 0) {
75                         _E("System session is not ready yet.");
76                         return;
77                 }
78                 CRITICAL_LOG("System session is ready.");
79                 device_notify_once(DEVICE_NOTIFIER_DELAYED_INIT, &system_done);
80
81         } else if (strcmp(name, SYSTEMD_DBUS_SIGNAL_USER_STARTUP_FINISHED) == 0) {
82                 if (user_done)
83                         return;
84                 user_done = 1;
85                 _I("User session is ready.");
86         }
87
88         if (!system_done || !user_done)
89                 return;
90
91         remove_delayed_init_done_handler(NULL);
92
93         doze_init();
94 }
95
96 void add_delayed_init_done_handler(void *data)
97 {
98         /* System Session is loaded completely */
99         /*ret = */
100         sig_id[0] = gdbus_signal_subscribe(NULL,
101                                         SYSTEMD_DBUS_PATH,
102                                         SYSTEMD_DBUS_IFACE_MANAGER,
103                                         SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED,
104                                         delayed_init_done_received,
105                                         NULL, NULL);
106
107         if (sig_id[0] <= 0)
108                 _E("Failed to init dbus signal(%s).", SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED);
109
110         /* User Session is loaded completely */
111         sig_id[1] = gdbus_signal_subscribe(NULL,
112                                         SYSTEMD_DBUS_PATH,
113                                         SYSTEMD_DBUS_IFACE_MANAGER,
114                                         SYSTEMD_DBUS_SIGNAL_USER_STARTUP_FINISHED,
115                                         delayed_init_done_received,
116                                         NULL, NULL);
117
118         if (sig_id[1] <= 0)
119                 _E("Failed to init dbus signal(%s).", SYSTEMD_DBUS_SIGNAL_USER_STARTUP_FINISHED);
120 }
121
122 static void parse_transition_info(const char *action)
123 {
124         char curr[16] = { 0, };
125         char next[16] = { 0, };
126
127         if (sscanf(action, "%15[^,],%15s", curr, next) == 2) {
128                 initial_transition_info.curr = convert_action_string_to_psm_state(curr);
129                 initial_transition_info.next = convert_action_string_to_psm_state(next);
130         }
131 }
132
133 static void parse_initial_transition_info(const struct parse_result *result)
134 {
135         GList *elem;
136         struct section_property *prop;
137
138         SYS_G_LIST_FOREACH(result->props, elem, prop) {
139                 if (MATCH(prop->key, "Enum"))
140                         initial_transition_info.reason = atoi(prop->value);
141                 else if (MATCH(prop->key, "Action"))
142                         parse_transition_info(prop->value);
143         }
144 }
145
146 static int parse_matching_bootreason(const struct parse_result *result, void *data)
147 {
148         GList *elem;
149         struct section_property *prop;
150         char *bootreason = (char *) data;
151
152         if (!MATCH(result->section, "EventAction"))
153                 return 0;
154
155         SYS_G_LIST_FOREACH(result->props, elem, prop) {
156                 if (MATCH(prop->key, "BootReason") && MATCH(prop->value, bootreason))
157                         parse_initial_transition_info(result);
158         }
159
160         return 0;
161 }
162
163 /* the initial transition by bootreason is defined in init.conf */
164 void get_initial_transition_by_bootreason(void *data)
165 {
166         int retval;
167         char bootreason[64] = "Unknown";
168         GList **head = (GList **) data;
169
170         if (!head)
171                 return;
172
173         retval = hal_device_board_get_boot_reason(bootreason, sizeof(bootreason));
174         if (retval == 0)
175                 libsys_config_parse_by_section(INIT_CONF_PATH, parse_matching_bootreason, bootreason);
176
177         CRITICAL_LOG("BootReason=%s", bootreason);
178
179         *head = g_list_append(*head, &initial_transition_info);
180 }