blob: c2e3e8ffdd137d3232d3242a190e7cb15a0fd1b2 [file] [log] [blame]
shu.wang4beb3d62022-06-28 14:46:29 +08001/*
2 * Copyright (c) 2022 Amlogic, Inc. All rights reserved.
3 * This source code is subject to the terms and conditions defined
4 * in the file 'LICENSE' which is part of this source code package.
5 * Description: auto shutdown file
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <fcntl.h>
12#include <sys/socket.h>
13#include <linux/netlink.h>
14#include <poll.h>
15#include <sys/ioctl.h>
16#include <sys/types.h>
17#include <unistd.h>
18#include <linux/input.h>
19#include <netinet/in.h>
20#include <sys/un.h>
21#include <errno.h>
22#include <pthread.h>
23#include <sys/time.h>
24#include <signal.h>
25#include <dirent.h>
26
27#define INFO(fmt, args...) \
28 printf("[Auto Shutdown][%s] " fmt, __func__, ##args)
29
30/*timer*/
shu.wang91e37e82022-07-04 13:50:23 +080031#define POWER_OFF_TIME_DEFAULT (45) //45min
32#define POWER_OFF_TIME_MIN (5) //5min
33#define POWER_OFF_TIME_MAX (90) //90min
34#define MIN_TO_SEC (60) //60s
35#define POWER_OFF_TIME_TO_SEC_DEFAULT (POWER_OFF_TIME_DEFAULT * MIN_TO_SEC)
shu.wang4beb3d62022-06-28 14:46:29 +080036
37/*usb*/
38#define UEVENT_BUFFER_SIZE 2048
39#define MIN_SIZE 30
40#define USB_STATE_FILE "/sys/class/android_usb/android0/state"
41
42/*bt*/
43#define CTL_SOCKET_PATH "/etc/bluetooth/hfp_ctl_sk"
44#define HFP_EVENT_CONNECTION 1
45#define HFP_EVENT_CALL 2
46#define HFP_EVENT_CALLSETUP 3
47#define HFP_EVENT_VGS 4
48#define HFP_EVENT_VGM 5
49
50#define HFP_IND_DEVICE_DISCONNECTED 0
51#define HFP_IND_DEVICE_CONNECTED 1
52
53#define HFP_IND_CALL_NONE 0
54/* at least one call is in progress */
55#define HFP_IND_CALL_ACTIVE 1
56/* currently not in call set up */
57#define HFP_IND_CALLSETUP_NONE 0
58/* an incoming call process ongoing */
59#define HFP_IND_CALLSETUP_IN 1
60/* an outgoing call set up is ongoing */
61#define HFP_IND_CALLSETUP_OUT 2
62/* remote party being alerted in an outgoing call */
63#define HFP_IND_CALLSETUP_OUT_ALERT 3
64
65/*adc key*/
66#define ADC_INPUT_EVENT_NAME "adc_keypad"
67
68#define USB_DISCONNECT 0
69#define USB_CONNECT 1
70
71#define HFP_STATE_DISCONNECT 0 //handfree disconnect
72#define HFP_STATE_CONNECT 1 //handfree connect
73#define HFP_STATE_CALL_IN 2 //have call in
74#define HFP_STATE_CALL_OUT 3 //have call out
75#define HFP_STATE_CALL_OUT_RINGING 4 //call out,ringing
76#define HFP_STATE_CALL_IN_OUT_OVER 5 //call in and out over
77#define HFP_STATE_CALL_START 6 //call start
78#define HFP_STATE_CALL_ENDED 7 //call over
79
80static int usb_state = USB_CONNECT;
81static int bt_state = HFP_STATE_DISCONNECT;
shu.wang91e37e82022-07-04 13:50:23 +080082static int timing_time_sec = POWER_OFF_TIME_TO_SEC_DEFAULT;
shu.wang4beb3d62022-06-28 14:46:29 +080083
84static int stop_timer(void);
85static int check_to_start_timer(void);
86
87static int usb_monitor_init(void)
88{
89 struct sockaddr_nl client;
90 int usb_monitor, ret;
91 int buffersize = 1024;
92 usb_monitor = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
93 if (0 > usb_monitor) {
94 return -1;
95 }
96
97 memset(&client, 0, sizeof(client));
98 client.nl_family = AF_NETLINK;
99 client.nl_pid = getpid();
100 client.nl_groups = 1; /* receive broadcast message*/
101 ret = setsockopt(usb_monitor, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
102 if (0 > ret) {
103 return -1;
104 }
105 ret = bind(usb_monitor, (struct sockaddr*)&client, sizeof(client));
106 if (0 > ret) {
107 return -1;
108 }
109 return usb_monitor;
110}
111
112static int usb_state_change(void)
113{
114 char usb_state_buffer[MIN_SIZE] = {0};
115 FILE *fp = fopen(USB_STATE_FILE, "r");
116 if (fp != NULL) {
117 if (fgets(usb_state_buffer, MIN_SIZE, fp) == NULL) {
118 INFO("get android0 state content failure!\n");
119 fclose(fp);
120 } else {
121 if (!strncmp("DISCONNECTED", (const char*)usb_state_buffer, strlen("DISCONNECTED"))) {
122 INFO("usb is disconnected!\n");
123 usb_state = USB_DISCONNECT;
124 check_to_start_timer();
125 } else if (!strncmp("CONFIGURED", (const char*)usb_state_buffer, strlen("CONFIGURED"))) {
126 INFO("usb is connected!\n");
127 usb_state = USB_CONNECT;
128 stop_timer();
129 }
130 fclose(fp);
131 }
132 } else {
133 INFO("can't open usb state file!\n");
134 }
135 fp = NULL;
136 return 0;
137}
138
139static int usb_state_read(int fd)
140{
141 int rcvlen;
142 int buffersize = 1024;
143 char buf[UEVENT_BUFFER_SIZE] = {0};
144 /* receive data */
145 rcvlen = recv(fd, &buf, sizeof(buf), 0);
146 if (rcvlen > 0 && strstr(buf,"usb") ) {
147 //printf("%s\n", buf);
148 usb_state_change();
149 }
150 return 0;
151}
152
153static int bt_monitor_init(void)
154{
155 struct sockaddr_un address;
156 int sockfd;
157
158 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
159 INFO("can't creat socket, errno:%s", strerror(errno));
160 return -1;
161 }
162
163 address.sun_family = AF_UNIX;
164 strncpy (address.sun_path, CTL_SOCKET_PATH, sizeof(address.sun_path) - 1);
165
166 if (connect(sockfd, (struct sockaddr *)&address, sizeof (address)) == -1) {
167 /*if socket is not avialable or not ready, don't report error*/
168 if (errno != 111 && errno != 2)
169 INFO("connect server: %s", strerror(errno));
170 close(sockfd);
171 return -1;
172 }
173 return sockfd;
174}
175
176static void msg_handler(int event, int value)
177{
178 switch (event) {
179 case HFP_EVENT_CONNECTION:
180 switch (value) {
181 case HFP_IND_DEVICE_DISCONNECTED:
182 INFO("HFP disconnected!!!\n");
183 bt_state = HFP_STATE_DISCONNECT;
184 check_to_start_timer();
185 break;
186
187 case HFP_IND_DEVICE_CONNECTED:
188 INFO("HFP connected!!!\n");
189 bt_state = HFP_STATE_CONNECT;
190 stop_timer();
191 break;
192
193 default:
194 break;
195 }
196 break;
197
198 case HFP_EVENT_CALL:
199 switch (value) {
200 case HFP_IND_CALL_NONE:
201 INFO("Call stopped!!!\n");
202 bt_state = HFP_STATE_CALL_START;
203 break;
204
205 case HFP_IND_CALL_ACTIVE :
206 INFO("Call active!!!\n");
207 bt_state = HFP_STATE_CALL_ENDED;
208 break;
209
210 default:
211 break;
212 }
213 break;
214
215 case HFP_EVENT_CALLSETUP:
216 switch (value) {
217 case HFP_IND_CALLSETUP_NONE:
218 INFO("Callsetup stopped!!!\n");
219 if (bt_state != HFP_STATE_CALL_START)
220 bt_state = HFP_STATE_CALL_IN_OUT_OVER;
221 break;
222
223 case HFP_IND_CALLSETUP_IN :
224 INFO("An incomming Callsetup!!!\n");
225 bt_state = HFP_STATE_CALL_IN;
226 break;
227
228 case HFP_IND_CALLSETUP_OUT :
229 INFO("An outgoing Callsetup!!!\n");
230 bt_state = HFP_STATE_CALL_OUT;
231 break;
232
233 case HFP_IND_CALLSETUP_OUT_ALERT :
234 INFO("Remote device being altered!!!\n");
235 bt_state = HFP_STATE_CALL_OUT_RINGING;
236 break;
237
238 default:
239 break;
240 }
241 break;
242
243 default:
244 break;
245 }
246}
247
248static int bt_state_read(int fd)
249{
250 char msg[64];
251 int byte, i, value = -1, event =-1;
252 if (fd < 0) {
253 INFO("BT fd is error!\n");
254 return -1;
255 }
256 memset(msg, 0, sizeof(msg));
257 byte = recv(fd, msg, sizeof(msg), 0);
258 if (byte < 0) {
259 INFO("rcv error!\n");
260 } else if (byte == 0) {
261 INFO("the server is offline, need to reconnect!\n");
262 bt_state = HFP_STATE_DISCONNECT;
263 check_to_start_timer();
264 return -1;
265 } else if (byte >= 2) {
266 INFO("incoming msg of %d bytes\n", byte);
267 for (i = 0; i + 1 < byte; i += 2) {
268 event = msg[i];
269 value = msg[i + 1];
270 INFO("event = %d, value = %d\n", event, value);
271 msg_handler(event, value);
272 }
273 }
274 return 0;
275}
276
277static void *bt_monitor_pthread(void * arc)
278{
279 int bt_fd, res;
280 struct pollfd pollfds;
281init:
282 if ((bt_fd = bt_monitor_init()) < 0) {
283 sleep(5);
284 goto init;
285 }
286
287 pollfds.fd = bt_fd;
288 pollfds.events = POLLIN;
289 while (1) {
290 poll(&pollfds, 1, -1);
291 if (pollfds.revents & POLLIN) {
292 pollfds.revents = 0;
293 res=bt_state_read(bt_fd);
294 if (res < 0) {
295 close(bt_fd);
296 goto init;
297 }
298 }
299 }
300 close(bt_fd);
301 return NULL;
302}
303
304static int key_monitor_init(void)
305{
306 int fd = -1;
307 char name[256];
308 DIR* dir = opendir("/dev/input");
309 if (dir != NULL) {
310 struct dirent* de;
311 while ((de = readdir(dir))) {
312 if (strncmp(de->d_name, "event", 5)) continue;
313 fd = openat(dirfd(dir), de->d_name, O_RDONLY);
314 if (fd < 0) continue;
315 ioctl(fd, EVIOCGNAME(sizeof(name)), name);
316 if (!strcmp(ADC_INPUT_EVENT_NAME, name))
317 break;
318 close(fd);
319 fd = -1;
320 }
321 closedir(dir);
322 }
323 return fd;
324}
325
326static int key_state_read(int fd)
327{
328 int rd, i;
329 struct input_event ev[5];
330
331 if (fd < 0) {
332 INFO("ADC-KEY fd is error!\n");
333 return -1;
334 }
335
336 memset(ev, 0, sizeof(ev));
337 rd = read(fd, ev, sizeof(ev));
338
339 if (rd < (int) sizeof(struct input_event)) {
340 INFO("expected %d bytes, got %d\n", (int) sizeof(struct input_event), rd);
341 perror("\nevtest: error reading");
342 return 1;
343 }
344
345 for (i = 0; i < rd / sizeof(struct input_event); i++) {
346 if (ev[i].type !=0 ) {
347 if (ev[i].value == 1) {
348 INFO("Have a key press!\n");
349 stop_timer();
350 } else if (ev[i].value == 0) {
351 INFO("Have a key release!\n");
352 check_to_start_timer();
353 }
354 }
355 }
356 return 0;
357}
358
359static void timer_handle(int sig)
360{
361 system("/etc/adckey/adckey_function.sh longpresspower");
362}
363
364static int set_timer_handle(void (*fun)(int))
365{
366 if (fun == NULL)
367 return -1;
368 signal(SIGALRM, fun);
369 return 0;
370}
371
372static int start_timer(unsigned int nsec)
373{
374 struct itimerval tick;
375 memset(&tick, 0, sizeof(tick));
376 tick.it_value.tv_sec = nsec;
377 tick.it_value.tv_usec = 0;
378
379 tick.it_interval.tv_sec = 0;
380 tick.it_interval.tv_usec = 0;
381
382 if (setitimer(ITIMER_REAL, &tick, NULL) < 0) {
383 INFO("Set timer failed!\n");
384 return -1;
385 }
386 INFO("Start timer!\n");
387 return 0;
388}
389
390static int stop_timer(void)
391{
392 struct itimerval tick;
393 memset(&tick, 0, sizeof(tick));
394 tick.it_value.tv_sec = 0;
395 tick.it_value.tv_usec = 0;
396
397 tick.it_interval.tv_sec = 0;
398 tick.it_interval.tv_usec = 0;
399
400 if (setitimer(ITIMER_REAL, &tick, NULL) < 0) {
401 INFO("Set timer failed!\n");
402 return -1;
403 }
404 INFO("Stop timer!\n");
405 return 0;
406}
407
408static int check_to_start_timer(void)
409{
410 if (usb_state == USB_DISCONNECT
411 && bt_state == HFP_STATE_DISCONNECT)
shu.wang91e37e82022-07-04 13:50:23 +0800412 start_timer(timing_time_sec);
shu.wang4beb3d62022-06-28 14:46:29 +0800413 return 0;
414}
415
shu.wang91e37e82022-07-04 13:50:23 +0800416int main(int argc, char **argv)
shu.wang4beb3d62022-06-28 14:46:29 +0800417{
418 int usb_fd, key_fd;
shu.wang91e37e82022-07-04 13:50:23 +0800419 int timing_time_min;
shu.wang4beb3d62022-06-28 14:46:29 +0800420 pthread_t bt_thread_id;
421 struct pollfd pollfds[2];
shu.wang91e37e82022-07-04 13:50:23 +0800422 const char *cmd_usage = {
423 "Usage:\n"
424 "\t Automatic shutdown when idle \n"
425 "\t auto_shutdown <Timing time> \n"
426 "\t <Timing time>: 5 ~ 90\n"
427 "\t MIN:5min MAX:90min Default:45min\n"
428 };
429
430 if (argc != 2) {
431 printf("%s", cmd_usage);
432 return -1;
433 }
434
435 if ((timing_time_min = atoi(argv[1])) != 0) {
436 if (timing_time_min < POWER_OFF_TIME_MIN || timing_time_min > POWER_OFF_TIME_MAX)
437 timing_time_min = POWER_OFF_TIME_DEFAULT;
438 } else {
439 timing_time_min = POWER_OFF_TIME_DEFAULT;
440 }
441 INFO("Timing time: %d min\n", timing_time_min);
442 timing_time_sec = timing_time_min * MIN_TO_SEC;
shu.wang4beb3d62022-06-28 14:46:29 +0800443
444 memset(pollfds, 0, sizeof(pollfds));
445 /*usb*/
446 usb_fd = usb_monitor_init();
447 if (usb_fd > 0) {
448 pollfds[0].fd = usb_fd;
449 pollfds[0].events = POLLIN;
450 usb_state_change();
451 check_to_start_timer();
452 }
453 /*adc-key*/
454 key_fd = key_monitor_init();
455 if (key_fd > 0) {
456 pollfds[1].fd = key_fd;
457 pollfds[1].events = POLLIN;
458 }
459 /*bt*/
460 int res = pthread_create(&bt_thread_id, NULL, bt_monitor_pthread, NULL);
461 if (res < 0)
462 INFO("bt monitor pthread creat fail!\n");
463
464 set_timer_handle(timer_handle);
465 while (1)
466 {
467 poll(pollfds, 2, -1);
468
469 for (int i = 0; i < 2; i++) {
470 if (pollfds[i].revents & POLLIN) {
471 pollfds[i].revents = 0;
472 if (pollfds[i].fd == usb_fd)
473 usb_state_read(usb_fd);
474 else if (pollfds[i].fd == key_fd)
475 key_state_read(key_fd);
476 }
477 }
478 }
479 if (key_fd > 0)
480 close(key_fd);
481 if (usb_fd > 0)
482 close(usb_fd);
483}