blob: f706c9f8205648a7c18faa3e62778b138057eb0e [file] [log] [blame]
/* //device/system/rild/rild.c
**
** Copyright 2006 The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <dlfcn.h>
#include <string.h>
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <log/log.h>
#include <liblog/lynq_deflog.h>
#include <include/lynq_uci.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#define LOG_UCI_MODULE "lynq_autosuspend"
#define LOG_UCI_FILE "lynq_uci"
#define LOG_TAG "AUTOSUSPEND"
#define USER_LOG_TAG "PMS"
#define SOCK_PATH "/tmp/autosuspend.cmd.server" //不能在当前这个目录创建socket文件,否则报错找不到文件(可能是因为这是在共享文件夹下,不支持创建socket文件)
#define SOCK_DATA_PATH "/tmp/autosuspend.data.server"
// #define LYINFLOG(X...) lynq_log_global_output(LOG_INFO,X)
#define TIME_OUT_TIME 30
#define MAX_LIB_ARGS 16
int adb_debug_mode = 0;
pthread_cond_t feedback_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t feedback_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t time_info_mutex = PTHREAD_MUTEX_INITIALIZER;
extern int autosuspend_enable(void);
extern int autosuspend_disable(void);
extern void init_wakelock_func(void);
extern void init_sim_func();
extern void init_network_func();
extern void set_wakeup_callback(void (*func)(bool success));
extern void wakeup_feedback(bool success);
extern int (*lynq_screen)(int num);
struct time_info_t
{
long sleep_start_time;
long wakeup_time;
};
struct time_info_t time_info;
static void usage(const char *argv0) {
fprintf(stderr, "Usage: %s -l <possible_max_sleep_time> [-- <args for Autosuspend Service>]\n", argv0);
exit(EXIT_FAILURE);
}
static int make_argv(char * args, char ** argv) {
// Note: reserve argv[0]
int count = 1;
char * tok;
char * s = args;
while ((tok = strtok(s, " \0"))) {
argv[count] = tok;
s = NULL;
count++;
}
return count;
}
static int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
int n;
while((n = accept(fd, sa, salenptr)) < 0)
{
if((errno == ECONNABORTED) || (errno == EINTR))
continue;
else
{
ALOGI("accept error\n");
return -1;
}
}
return n;
}
static int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if(bind(fd, sa, salen) < 0)
{
// ALOGI("bind error\n");
perror("bind error");
return -1;
}
return 0;
}
static int Socket(int family, int type, int protocol)
{
int n;
if ( (n = socket(family, type, protocol)) < 0)
{
ALOGI("socket error\n");
return -1;
}
return n;
}
static int Listen(int fd, int backlog)
{
if(listen(fd, backlog) < 0)
{
ALOGI("listen error\n");
return -1;
}
return 0;
}
static int listen_port(struct sockaddr_un *addr, char *sockpath)
{
int listenfd;
listenfd = Socket(AF_UNIX,SOCK_STREAM,0);
if(listenfd == -1)
return -1;
memset(addr, 0, sizeof(struct sockaddr_un));
addr->sun_family = AF_UNIX;
strcpy(addr->sun_path,sockpath);
// int opt = 1;
// if(setsockopt(listenfd, SOL_SOCKET,SO_REUSEADDR, (const void *)&opt, sizeof(opt)) == -1)
// {
// perror("setsockopt error");
// return -1;
// }
// 以上方法对非网络的本地socket无效,应该用unlink函数避免Address already in use的错误
unlink(sockpath);
if(Bind(listenfd,(struct sockaddr *)addr,sizeof(*addr)) == -1)
return -1;
if(Listen(listenfd,20) == -1)
return -1;
return listenfd;
}
static ssize_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;
while((n = read(fd, ptr, nbytes)) == -1)
{
//printf("READ,%d\n",fd);
if (errno == EINTR)
{
ALOGI("read error eintr\n");
continue;
}
else if(errno == EAGAIN || errno == EWOULDBLOCK)
{
ALOGI("read time out\n");
return -1;
}
else
{
ALOGI("read error\n");
return -1;
}
}
//sleep(2);
//printf("READ1,%d\n", fd);
return n;
}
static ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
ssize_t n;
while((n = write(fd, ptr, nbytes)) == -1)
{
if (errno == EINTR)
continue;
else if(errno == EPIPE)
{
ALOGI("write error epipe\n");
return -1;
}
else
return -1;
}
return n;
}
static int Close(int fd)
{
if (close(fd) == -1)
{
ALOGI("close error\n");
return -1;
}
return 0;
}
void *deal_autosuspend(void *sockfd)
{
int commfd = *((int *)sockfd);
char buf[20];
char res[15];
while(1)
{
memset(buf,0,sizeof(buf));
ALOGI("deal_autosuspend start to read.\n");
// 错误点:read函数在对端关闭后,也会直接返回0,不会阻塞,因此要判断是否返回0,返回0表示对端已经关闭,此时要跳出while循环不再监听
// 为什么对端会关闭?因为在客户端没有用nohup方式打开的情况下,系统睡眠后客户端进行会直接被杀死,对端会关闭,所以会导致read不阻塞,且总是返回0的现象
if(Read(commfd,buf,sizeof(buf)) <= 0)
{
ALOGI("service receive suspend_cmd fail or client is closed.\n");
Close(commfd);
break;
}
if(strcmp(buf,"enable") == 0)
{
if(autosuspend_enable() < 0)
{
ALOGI("autosuspend_enable fail.\n");
}
else
{
ALOGI("autosuspend_enable success.\n");
}
}
else if(strcmp(buf,"disable") == 0)
{
if(autosuspend_disable() < 0)
{
ALOGI("autosuspend_disable fail.\n");
}
else
{
ALOGI("autosuspend_disable success.\n");
}
}
else
{
ALOGI("Unknown cmd : %s\n",buf);
}
}
}
#ifdef GSW_SUSPEND_CFG
/*jb.qi add for service send when DTR is low on 20221111 start */
void *dtr_wakeup()
{
FILE *fp;
int ret;
bool success = true;
char buf[30];
char dtr_buffer[25];
RLOGD("dtr_wakeup start\n");
while(1)
{
fp = popen("cat /sys/devices/platform/10005000.pinctrl/mt_gpio |grep 006:","r");
fgets(dtr_buffer, sizeof(dtr_buffer), fp);
if(dtr_buffer[7] == '0')
{
time_info.sleep_start_time = 123;
time_info.wakeup_time = 123;
if (pthread_cond_broadcast(&feedback_cond) != 0)
{
strerror_r(errno, buf, sizeof(buf));
ALOGI("Error broadcast cond: %s\n", buf);
}
RLOGD("dtr_wakeup success!\n");
sleep(3);
}
usleep(500);
pclose(fp);
}
}
/*jb.qi add for service send when DTR is low on 20221111 end */
#endif
void *send_feedback(void *sockfd)
{
int commfd = *((int *)sockfd);
char buf[80];
while (1)
{
memset(buf,0,sizeof(buf));
ALOGI("send_feedback thread wait to send.\n");
pthread_mutex_lock(&feedback_mutex);
pthread_cond_wait(&feedback_cond,&feedback_mutex);
ALOGI("send_feedback thread is now sending the feedback to client.\n");
pthread_mutex_lock(&time_info_mutex);
if(Write(commfd,&time_info,sizeof(struct time_info_t)) <= 0)
{
ALOGI("service send wakeup_feedback struct fail.\n");
Close(commfd);
pthread_mutex_unlock(&time_info_mutex);
pthread_mutex_unlock(&feedback_mutex);
#ifdef GSW_SUSPEND_CFG
continue ;//jb.qi add for service send when DTR is low on 20221111
#endif
#ifdef MOBILETEK_SUSPEND_CFG
break ;
#endif
}
pthread_mutex_unlock(&time_info_mutex);
pthread_mutex_unlock(&feedback_mutex);
}
}
int main(int argc, char **argv) {
// int i = 0;
// RLOGD("**Autosuspend Service Daemon Started**");
// RLOGD("**Autosuspend Service param count=%d**", argc);
char tmp[20];
int commfd, commfd_data, server_sock, server_data_sock,len, len_data;
struct sockaddr_un server_sockaddr;
struct sockaddr_un server_data_sockaddr;
struct sockaddr_un client_sockaddr;
len = sizeof(server_sockaddr);
pthread_t tid;
#ifdef GSW_SUSPEND_CFG
pthread_t tid_1;//jb.qi add for service send when DTR is low on 20221111
#endif
LYLOGEINIT(USER_LOG_TAG);
LYLOGSET(LOG_DEBUG);
// LYLOGSET(LOG_ERROR);
int auto_enable = 0;
lynq_get_value(LOG_UCI_FILE, LOG_UCI_MODULE, "debug", tmp); // 即获取系统层面的环境变量
ALOGI("Autosuspend Service Daemon. debug %s\n",tmp);
adb_debug_mode=atoi(tmp);
lynq_get_value(LOG_UCI_FILE, LOG_UCI_MODULE, "auto_enable", tmp);
auto_enable=atoi(tmp);
ALOGI("Autosuspend Service Daemon. auto_enable %s\n",tmp);
#ifdef MOBILETEK_SUSPEND_CFG
init_wakelock_func();
init_sim_func();
#endif
signal(SIGPIPE,SIG_IGN); // 忽略SIGPIPE信号,防止由于客户端关闭,继续往客户端write,会导致服务端收到SIGPIPE信号而Broken pipe
// init_network_func();
// if(pthread_cond_init(&feedback_cond,NULL) != 0)
// {
// strerror_r(errno, buf, sizeof(buf));
// ALOGI("Error creating cond: %s\n", buf);
// return -1;
// }
set_wakeup_callback(wakeup_feedback);
// 注册回调函数
if(auto_enable==0)
{
if(autosuspend_disable() < 0)
{
ALOGI("autosuspend_disable fail.\n");
}
else
{
ALOGI("autosuspend_disable success.\n");
}
}
if(auto_enable==1)
{
if(autosuspend_enable() < 0)
{
ALOGI("autosuspend_enable fail.\n");
}
else
{
ALOGI("autosuspend_enable success.\n");
}
}
server_sock = listen_port(&server_sockaddr,SOCK_PATH);
if(server_sock == -1)
return -1;
server_data_sock = listen_port(&server_data_sockaddr,SOCK_DATA_PATH);
if(server_data_sock == -1)
return -1;
#ifdef GSW_SUSPEND_CFG
/*jb.qi add for service send when DTR is low on 20221111 start*/
pthread_create(&tid_1,NULL,dtr_wakeup,NULL);
pthread_detach(tid_1);
/*jb.qi add for service send when DTR is low on 20221111 end*/
#endif
while (1)
{
ALOGI("service socket listening...\n");
commfd = Accept(server_sock,(struct sockaddr *)&client_sockaddr,&len);
if(commfd == -1)
{
return -1;
}
if(getpeername(commfd, (struct sockaddr *)&client_sockaddr, &len) == -1)
{
ALOGI("GETPEERNAME ERROR.\n");
// Close(server_sock);
Close(commfd);
continue;
}
else
{
ALOGI("Client socket filepath: %s\n", client_sockaddr.sun_path);
}
commfd_data = Accept(server_data_sock,NULL,NULL);
if(commfd_data == -1)
{
return -1;
}
ALOGI("data channel connected.\n");
pthread_create(&tid,NULL,deal_autosuspend,(void*)&commfd);//这里很容易错,最后一个参数要取地址,这是一个指针
pthread_detach(tid);
pthread_create(&tid,NULL,send_feedback,(void*)&commfd_data);
pthread_detach(tid);
}
}
DEFINE_LYNQ_LIB_LOG(LYNQ_AUTOSUSPEND)