/******************************************************************************
|
*
|
* Copyright (C) 2020-2021 SeekWave Technology
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
*
|
******************************************************************************/
|
|
#include <pthread.h>
|
#include <errno.h>
|
#include <utils/Log.h>
|
#include <sys/inotify.h>
|
#include <sys/epoll.h>
|
#include <sys/socket.h>
|
|
#include <string.h>
|
#include <unistd.h>
|
#include "skw_common.h"
|
#include "skw_ext.h"
|
|
#define SKW_EXT_BUF_SIZE 2048
|
|
typedef struct
|
{
|
pthread_t thread_id;
|
char thread_running;
|
int epoll_fd;
|
int signal_fd[2];
|
} skw_inotify_thread_info_st;
|
|
skw_inotify_thread_info_st skw_inotify_thread_info;
|
|
|
extern void scomm_vendor_write_wakeup_adv_enable();
|
|
|
/*
|
struct inotify_event {
|
int wd; // Watch descriptor
|
uint32_t mask; // Mask of events
|
uint32_t cookie; // Unique cookie associating related events (for rename(2))
|
uint32_t len; // Size of name field
|
char name[]; // Optional null-terminated name
|
};
|
*/
|
|
/*******************************************************************************
|
**
|
** Function skw_ext_inotify_thread
|
**
|
** Description inotify thread function
|
**
|
** Returns void *
|
**
|
*******************************************************************************/
|
static void *skw_ext_inotify_thread(void *arg)
|
{
|
int fd = -1;
|
int wd = -1;
|
int read_len = 0;
|
int event_pos = 0;
|
int event_size = 0;
|
char buffer[SKW_EXT_BUF_SIZE + 1] = {0};
|
struct inotify_event *event = NULL;
|
skw_inotify_thread_info_st *thread_info = &skw_inotify_thread_info;
|
|
int epfd = epoll_create(4);
|
struct epoll_event ev;
|
struct epoll_event events[20];
|
|
SKWBT_LOG("%s enter", __func__);
|
|
SKW_UNUSED(arg);
|
fd = inotify_init1(IN_NONBLOCK);
|
if(fd < 0)
|
{
|
ALOGE("inotify_init1 failed: %s", strerror(errno));
|
return NULL;
|
}
|
wd = inotify_add_watch(fd, "/dev", IN_CREATE);
|
if (wd < 0)
|
{
|
ALOGE("inotify_add_watch fail: %s\n", strerror(errno));
|
return NULL;
|
}
|
if(socketpair(AF_UNIX, SOCK_STREAM, 0, thread_info->signal_fd) == -1)
|
{
|
ALOGE("signal socket creare fail: %s\n", strerror(errno));
|
return NULL;
|
}
|
thread_info->epoll_fd = epfd;
|
|
memset(&ev, 0, sizeof(ev));
|
ev.data.fd = fd;
|
ev.events = EPOLLIN | EPOLLET;
|
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
|
|
|
ev.events = EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
|
ev.data.fd = thread_info->signal_fd[0];
|
if (epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1)
|
{
|
ALOGE("%s unable to register signal fd %d to epoll set: %s", __func__, ev.data.fd, strerror(errno));
|
return NULL;
|
}
|
|
while(thread_info->thread_running)
|
{
|
int nfds = epoll_wait(epfd, events, 20, 500);
|
for (int i = 0; i < nfds; ++i)
|
{
|
if(thread_info->thread_running == 0)
|
{
|
goto thread_exit;
|
}
|
if ((events[i].data.fd != fd) || (!(events[i].events & EPOLLIN)))
|
{
|
continue;
|
}
|
read_len = read(fd, buffer, SKW_EXT_BUF_SIZE);
|
|
//SKWBT_LOG("select read_len:%d, nfds:%d", read_len, nfds);
|
|
if(read_len <= 0)
|
{
|
continue;
|
}
|
event_pos = 0;
|
|
while((read_len >= (int)sizeof(struct inotify_event)) && (event_pos < SKW_EXT_BUF_SIZE))//may receive multiple events
|
{
|
event = (struct inotify_event *)(buffer + event_pos);
|
if(event->len)
|
{
|
if(event->mask & IN_CREATE)
|
{
|
SKWBT_LOG("recv command msg mask:0x%X name:%s", event->mask, event->name);
|
if (((event->mask & IN_ISDIR) == 0) && (memcmp(event->name, "shutdown", 8) == 0))
|
{
|
scomm_vendor_write_wakeup_adv_enable();
|
|
SKWBT_LOG("received shutdown command");
|
goto thread_exit;
|
}
|
}
|
else
|
{
|
SKWBT_LOG("othre event, mask:0x%X, name: %s", event->mask, event->name);
|
}
|
}
|
|
event_size = sizeof(struct inotify_event) + event->len;
|
read_len -= event_size;
|
event_pos += event_size;
|
}
|
|
}
|
}
|
|
thread_exit:
|
SKWBT_LOG("%s exit", __func__);
|
inotify_rm_watch(fd, wd);
|
close(fd);
|
thread_info->thread_running = FALSE;
|
return NULL;
|
}
|
|
/*******************************************************************************
|
**
|
** Function skw_ext_inotify_thread_init
|
**
|
** Description inotify thread init
|
**
|
** Returns None
|
**
|
*******************************************************************************/
|
void skw_ext_inotify_thread_init(void)
|
{
|
#if BLE_ADV_WAKEUP_ENABLE
|
skw_inotify_thread_info_st *thread_info = &skw_inotify_thread_info;
|
pthread_attr_t thread_attr;
|
pthread_attr_init(&thread_attr);
|
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
|
|
memset(thread_info, 0, sizeof(skw_inotify_thread_info_st));
|
SKWBT_LOG("%s enter", __func__);
|
|
thread_info->signal_fd[0] = -1;
|
thread_info->signal_fd[1] = -1;
|
if(pthread_create(&thread_info->thread_id, &thread_attr, skw_ext_inotify_thread, NULL) != 0)
|
{
|
ALOGE("%s pthread_create : %s", __func__, strerror(errno));
|
thread_info->thread_id = -1;
|
return ;
|
}
|
thread_info->thread_running = TRUE;
|
#else
|
SKW_UNUSED(skw_ext_inotify_thread);
|
#endif
|
}
|
|
/*******************************************************************************
|
**
|
** Function skw_ext_inotify_thread_exit
|
**
|
** Description inotify thread exit
|
**
|
** Returns None
|
**
|
*******************************************************************************/
|
void skw_ext_inotify_thread_exit(void)
|
{
|
#if BLE_ADV_WAKEUP_ENABLE
|
char is_closed = 0;
|
skw_inotify_thread_info_st *thread_info = &skw_inotify_thread_info;
|
|
if(thread_info->thread_running && (thread_info->thread_id != -1))
|
{
|
unsigned char close_signal = 1;
|
thread_info->thread_running = FALSE;
|
if(thread_info->epoll_fd >= 0)
|
{
|
ssize_t ret;
|
RW_NO_INTR(ret = write(thread_info->signal_fd[1], &close_signal, 1));
|
SKWBT_LOG("%s signal_fd:%d, ret:%d", __func__, thread_info->epoll_fd, (int)ret);
|
|
epoll_ctl(thread_info->epoll_fd, EPOLL_CTL_DEL, thread_info->signal_fd[0], NULL);
|
close(thread_info->signal_fd[0]);
|
close(thread_info->signal_fd[1]);
|
|
is_closed = 1;
|
}
|
pthread_join(thread_info->thread_id, NULL);
|
}
|
|
if(is_closed == 0)//The thread may have exited
|
{
|
if(thread_info->signal_fd[0] != -1)
|
{
|
close(thread_info->signal_fd[0]);
|
}
|
if(thread_info->signal_fd[1] != -1)
|
{
|
close(thread_info->signal_fd[1]);
|
}
|
}
|
if(thread_info->epoll_fd >= 0)
|
{
|
if(is_closed == 0)
|
{
|
epoll_ctl(thread_info->epoll_fd, EPOLL_CTL_DEL, thread_info->signal_fd[0], NULL);
|
}
|
close(thread_info->epoll_fd);
|
}
|
thread_info->signal_fd[0] = -1;
|
thread_info->signal_fd[1] = -1;
|
thread_info->epoll_fd = -1;
|
|
|
SKWBT_LOG("%s exit", __func__);
|
#endif
|
|
}
|