device-notifier: prevent index out of bound
[platform/core/system/deviced.git] / src / shared / device-notifier.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 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 <glib.h>
21 #include <errno.h>
22 #include "log.h"
23 #include "device-notifier.h"
24 #include "shared/common.h"
25 #include <libsyscommon/list.h>
26
27 #define __stringify_1(x...)     #x
28 #define __stringify(x...)       __stringify_1(x)
29
30 struct device_notifier {
31         int id;
32         int priority; /* descending order */
33         bool deleted;
34
35         enum device_notifier_type type;
36         int (*func)(void *data);
37
38         int (*func_udata)(void *data, void *user_data);
39         void (*destroyer)(void *user_data);
40         void *user_data;
41 };
42
43 static GList *device_notifier_list;
44 static guint idl;
45
46 #define FIND_NOTIFIER(a, b, d, e, f) \
47         SYS_G_LIST_FOREACH(a, b, d) \
48                 if (e == d->e && f == (d->f))
49
50 #define NOTIFY_STR(x)   [(x)] = __stringify((x))
51
52 static const char *device_notifier_type_str[DEVICE_NOTIFIER_MAX] = {
53         NOTIFY_STR(DEVICE_NOTIFIER_DAEMON_RESTARTED),
54         NOTIFY_STR(DEVICE_NOTIFIER_DELAYED_INIT),
55         NOTIFY_STR(DEVICE_NOTIFIER_LCD),
56         NOTIFY_STR(DEVICE_NOTIFIER_LCD_OFF),
57         NOTIFY_STR(DEVICE_NOTIFIER_LCD_OFF_COMPLETE),
58         NOTIFY_STR(DEVICE_NOTIFIER_LCD_AUTOBRT_SENSING),
59         NOTIFY_STR(DEVICE_NOTIFIER_LOWBAT),
60         NOTIFY_STR(DEVICE_NOTIFIER_FULLBAT),
61         NOTIFY_STR(DEVICE_NOTIFIER_POWER_SUPPLY),
62         NOTIFY_STR(DEVICE_NOTIFIER_BATTERY_HEALTH),
63         NOTIFY_STR(DEVICE_NOTIFIER_BATTERY_PRESENT),
64         NOTIFY_STR(DEVICE_NOTIFIER_BATTERY_OVP),
65         NOTIFY_STR(DEVICE_NOTIFIER_BATTERY_CHARGING),
66         NOTIFY_STR(DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED),
67         NOTIFY_STR(DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED),
68         NOTIFY_STR(DEVICE_NOTIFIER_DISPLAY_AMBIENT_CONDITION),
69         NOTIFY_STR(DEVICE_NOTIFIER_DISPLAY_AMBIENT_STATE),
70         NOTIFY_STR(DEVICE_NOTIFIER_DISPLAY_LOCK),
71         NOTIFY_STR(DEVICE_NOTIFIER_POWER_RESUME),
72         NOTIFY_STR(DEVICE_NOTIFIER_POWEROFF),
73         NOTIFY_STR(DEVICE_NOTIFIER_APPLICATION_BACKGROUND),
74         NOTIFY_STR(DEVICE_NOTIFIER_APPLICATION_FOREGROUND),
75         NOTIFY_STR(DEVICE_NOTIFIER_APPLICATION_TERMINATED),
76         NOTIFY_STR(DEVICE_NOTIFIER_USB_DEBUG_MODE),
77         NOTIFY_STR(DEVICE_NOTIFIER_USB_TETHERING_MODE),
78         NOTIFY_STR(DEVICE_NOTIFIER_EVENT_HANDLER),
79         NOTIFY_STR(DEVICE_NOTIFIER_CPU_BOOST_LOWBAT),
80         NOTIFY_STR(DEVICE_NOTIFIER_CPU_BOOST_POWEROFF),
81         NOTIFY_STR(DEVICE_NOTIFIER_PMQOS),
82         NOTIFY_STR(DEVICE_NOTIFIER_PMQOS_ULTRAPOWERSAVING),
83         NOTIFY_STR(DEVICE_NOTIFIER_PMQOS_POWERSAVING),
84         NOTIFY_STR(DEVICE_NOTIFIER_COOL_DOWN),
85         NOTIFY_STR(DEVICE_NOTIFIER_VITAL_STATE),
86         NOTIFY_STR(DEVICE_NOTIFIER_LONGKEY_RESTORE),
87         NOTIFY_STR(DEVICE_NOTIFIER_UPSM),
88         NOTIFY_STR(DEVICE_NOTIFIER_UPSM_OFF),
89         NOTIFY_STR(DEVICE_NOTIFIER_BEZEL_WAKEUP),
90         NOTIFY_STR(DEVICE_NOTIFIER_DISPLAY_BRIGHTNESS),
91         NOTIFY_STR(DEVICE_NOTIFIER_ULTRAPOWERSAVING),
92         NOTIFY_STR(DEVICE_NOTIFIER_EXTCON_COUNT),
93         NOTIFY_STR(DEVICE_NOTIFIER_KEY_PRESS),
94         NOTIFY_STR(DEVICE_NOTIFIER_KEY_RELEASE),
95
96         /* action triggered by input event */
97         NOTIFY_STR(DEVICE_NOTIFIER_INPUT_TRIGGER_POWEROFF),
98         NOTIFY_STR(DEVICE_NOTIFIER_INPUT_BROADCAST_SIGNAL),
99
100         /* Purpose of calling methods of different modules
101          * Use prefix DEVICE_NOTIFIER_REQUEST */
102         NOTIFY_STR(DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE),
103 };
104
105 static gint compare_priority(gconstpointer a, gconstpointer b)
106 {
107         /* descending order */
108         return ((const struct device_notifier *)b)->priority - ((const struct device_notifier *)a)->priority + 1;
109 }
110
111 int __register_notifier(enum device_notifier_type type, notify_cb func, int priority, const char *caller)
112 {
113         GList *n;
114         struct device_notifier *notifier;
115
116         if (type < DEVICE_NOTIFIER_MIN || type >= DEVICE_NOTIFIER_MAX)
117                 return -EINVAL;
118
119         _I("%s, %p by %s", device_notifier_type_str[type], func, caller);
120
121         if (!func) {
122                 _E("invalid func address! by %s", caller);
123                 return -EINVAL;
124         }
125
126         FIND_NOTIFIER(device_notifier_list, n, notifier, type, func) {
127                 _E("function is already registered! [%s, %p] by %s",
128                     device_notifier_type_str[type], func, caller);
129                 return -EINVAL;
130         }
131
132         notifier = calloc(1, sizeof(struct device_notifier));
133         if (!notifier) {
134                 _E("Fail to malloc for %s notifier! by %s", device_notifier_type_str[type], caller);
135                 return -ENOMEM;
136         }
137
138         notifier->type = type;
139         notifier->priority = priority;
140         notifier->func = func;
141
142         device_notifier_list = g_list_insert_sorted(device_notifier_list, notifier, compare_priority);
143
144         return 0;
145 }
146
147 int __register_notifier_udata(enum device_notifier_type type,
148         notify_cb_udata func_udata, void *user_data,
149         destroy_cb_udata func_destroy_udata, int priority, const char *caller)
150 {
151         struct device_notifier *notifier;
152         static int id = 1;
153
154         if (type < DEVICE_NOTIFIER_MIN || type >= DEVICE_NOTIFIER_MAX)
155                 return -EINVAL;
156
157         _I("%s, %p by %s", device_notifier_type_str[type], func_udata, caller);
158
159         if (!func_udata) {
160                 _E("invalid func address! by %s", caller);
161                 return -EINVAL;
162         }
163
164         notifier = calloc(1, sizeof(struct device_notifier));
165         if (!notifier) {
166                 _E("Fail to malloc for %s notifier! by %s", device_notifier_type_str[type], caller);
167                 return -ENOMEM;
168         }
169
170         notifier->id = id;
171         notifier->priority = priority;
172         notifier->type = type;
173         notifier->func_udata = func_udata;
174         notifier->user_data = user_data;
175         notifier->destroyer = func_destroy_udata;
176
177         device_notifier_list = g_list_insert_sorted(device_notifier_list, notifier, compare_priority);
178
179         ++id;
180
181         return notifier->id;
182 }
183
184 int __unregister_notifier(enum device_notifier_type type, notify_cb func, const char *caller)
185 {
186         GList *n;
187         struct device_notifier *notifier;
188
189         if (type < DEVICE_NOTIFIER_MIN || type >= DEVICE_NOTIFIER_MAX)
190                 return -EINVAL;
191
192         if (!func) {
193                 _E("invalid func address of %s! by %s", device_notifier_type_str[type], caller);
194                 return -EINVAL;
195         }
196
197         FIND_NOTIFIER(device_notifier_list, n, notifier, type, func) {
198                 _I("[%s, %p] by %s", device_notifier_type_str[type], func, caller);
199                 notifier->deleted = true;
200         }
201
202         return 0;
203 }
204
205 int __unregister_notifier_udata(int id, const char *caller)
206 {
207         GList *n;
208         struct device_notifier *notifier;
209
210         SYS_G_LIST_FOREACH(device_notifier_list, n, notifier) {
211                 if (notifier->id == id) {
212                         if (notifier->destroyer)
213                                 notifier->destroyer(notifier->user_data);
214                         notifier->deleted = true;
215                 }
216         }
217
218         return 0;
219 }
220
221 static gboolean delete_unused_notifier_cb(void *data)
222 {
223         GList *n;
224         GList *next;
225         struct device_notifier *notifier;
226
227         SYS_G_LIST_FOREACH_SAFE(device_notifier_list, n, next, notifier) {
228                 if (notifier->deleted) {
229                         SYS_G_LIST_REMOVE_LIST(device_notifier_list, n);
230                         free(notifier);
231                 }
232         }
233
234         idl = 0;
235         return G_SOURCE_REMOVE;
236 }
237
238 void device_notify(enum device_notifier_type type, void *data)
239 {
240         GList *n;
241         struct device_notifier *notifier;
242
243         SYS_G_LIST_FOREACH(device_notifier_list, n, notifier) {
244                 if (!notifier->deleted && type == notifier->type) {
245                         if (notifier->func)
246                                 notifier->func(data);
247                         else if (notifier->func_udata)
248                                 notifier->func_udata(data, notifier->user_data);
249                 }
250         }
251
252         if (!idl)
253                 idl = g_idle_add(delete_unused_notifier_cb, NULL);
254 }
255
256 void device_notify_once(enum device_notifier_type type, void *data)
257 {
258         GList *n;
259         struct device_notifier *notifier;
260
261         SYS_G_LIST_FOREACH(device_notifier_list, n, notifier) {
262                 if (!notifier->deleted && type == notifier->type) {
263                         if (notifier->func) {
264                                 notifier->func(data);
265                         } else if (notifier->func_udata) {
266                                 notifier->func_udata(data, notifier->user_data);
267                                 if (notifier->destroyer)
268                                         notifier->destroyer(notifier->user_data);
269                         }
270
271                         notifier->deleted = true;
272                 }
273         }
274
275         if (!idl)
276                 idl = g_idle_add(delete_unused_notifier_cb, NULL);
277 }