| /* //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) |
| { |
| /* |
| system("echo 7 | emdlogger_ctrl"); |
| |
| if (lynq_screen(0) < 0) //notify ril for screen off |
| { |
| ALOGI("lynq_screen off fail\n"); |
| return -1; |
| } |
| |
| sleep(5);*/ |
| if(autosuspend_enable() < 0) |
| { |
| ALOGI("autosuspend_enable fail.\n"); |
| // strcpy(res,"fail"); |
| // if(Write(commfd,res,strlen(res)) <= 0) |
| // { |
| // ALOGI("service send respond fail.\n"); |
| // Close(commfd); |
| // break; |
| // } |
| } |
| else |
| { |
| ALOGI("autosuspend_enable success.\n"); |
| // strcpy(res,"enabled"); |
| // if(Write(commfd,res,strlen(res)) <= 0) |
| // { |
| // ALOGI("service send respond fail.\n"); |
| // Close(commfd); |
| // break; |
| // } |
| } |
| } |
| else if(strcmp(buf,"disable") == 0) |
| { |
| if(autosuspend_disable() < 0) |
| { |
| ALOGI("autosuspend_disable fail.\n"); |
| // strcpy(res,"fail"); |
| // if(Write(commfd,res,strlen(res)) <= 0) |
| // { |
| // ALOGI("service send respond fail.\n"); |
| // Close(commfd); |
| // break; |
| // } |
| } |
| else |
| { |
| ALOGI("autosuspend_disable success.\n"); |
| // strcpy(res,"disabled"); |
| // if(Write(commfd,res,strlen(res)) <= 0) |
| // { |
| // ALOGI("service send respond fail.\n"); |
| // Close(commfd); |
| // break; |
| // } |
| } |
| } |
| // else if(strcmp(buf,"feedback") == 0) |
| // { |
| |
| // ALOGI("send_feedback thread wait to send.\n"); |
| // if (pthread_cond_wait(&feedback_cond,&feedback_mutex) != 0) |
| // { |
| // strerror_r(errno, buf, sizeof(buf)); |
| // ALOGI("Error waiting on cond: %s\n", buf); |
| // Close(commfd); |
| // break; |
| // } |
| |
| // ALOGI("send_feedback thread is now sending the feedback to client.\n"); |
| // if(Write(commfd,&time_info,sizeof(struct time_info_t)) <= 0) |
| // { |
| // ALOGI("service send wakeup_feedback struct fail.\n"); |
| // Close(commfd); |
| // break ; |
| // } |
| // ALOGI("service send feedback success.\n"); |
| // strcpy(res,"success"); |
| // if(Write(commfd,res,strlen(res)) <= 0) |
| // { |
| // ALOGI("service send respond fail.\n"); |
| // Close(commfd); |
| // break; |
| // } |
| |
| // } |
| else |
| { |
| ALOGI("Unknown cmd : %s\n",buf); |
| } |
| |
| } |
| |
| |
| |
| } |
| /*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(500000); |
| pclose(fp); |
| } |
| } |
| /*jb.qi add for service send when DTR is low on 20221111 end */ |
| |
| 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); |
| continue ;//jb.qi add for service send when DTR is low on 20221111 |
| } |
| pthread_mutex_unlock(&time_info_mutex); |
| pthread_mutex_unlock(&feedback_mutex); |
| } |
| |
| } |
| |
| |
| void *check_wakeup_sources(void *sockfd) |
| { |
| FILE *fp; |
| int ret; |
| char buf[256]; |
| RLOGD("start check wakeup_sources !!!\n"); |
| while(1) |
| { |
| memset(buf,0,sizeof(buf)); |
| fp = popen("cat /sys/kernel/debug/wakeup_sources|sed -e 's/\"^ \"/\"unnamed\"/g' | awk '{print $6 \"\t\" $1}'| grep -v \"^0\" |sort -n \n","r"); |
| while(fgets(buf, 255, fp) != NULL) |
| { |
| RLOGD("%s", buf); |
| } |
| pclose(fp); |
| sleep(3); |
| } |
| } |
| |
| |
| 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,tid_1,tid_2; //jb.qi add for service send when DTR is low on 20221111 |
| |
| LYLOGEINIT(USER_LOG_TAG); |
| LYLOGSET(LOG_DEBUG); |
| // LYLOGSET(LOG_ERROR); |
| |
| int auto_enable = 0; |
| system("uci set lynq_uci.lynq_autosuspend.debug='0'");//jb.qi add for gsw close debug when power_on on 20231130 |
| 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); |
| init_wakelock_func(); |
| init_sim_func(); |
| |
| signal(SIGPIPE,SIG_IGN); // 忽略SIGPIPE信号,防止由于客户端关闭,继续往客户端write,会导致服务端收到SIGPIPE信号而Broken pipe |
| |
| 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; |
| |
| /*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*/ |
| |
| if(adb_debug_mode == 2) |
| { |
| pthread_create(&tid_2,NULL, check_wakeup_sources,NULL); |
| pthread_detach(tid_2); |
| } |
| |
| 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); |
| |
| |
| } |
| |
| /* for (i = 1; i < argc ;) { |
| if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) { |
| rilLibPath = argv[i + 1]; |
| i += 2; |
| } else if (0 == strcmp(argv[i], "--")) { |
| i++; |
| hasLibArgs = 1; |
| break; |
| } else if (0 == strcmp(argv[i], "-c") && (argc - i > 1)) { |
| clientId = argv[i+1]; |
| i += 2; |
| } else { |
| usage(argv[0]); |
| } |
| } |
| |
| if (clientId == NULL) { |
| clientId = "0"; |
| } else if (atoi(clientId) >= MAX_RILDS) { |
| RLOGE("Max Number of rild's supported is: %d", MAX_RILDS); |
| exit(0); |
| } |
| if (strncmp(clientId, "0", MAX_CLIENT_ID_LENGTH)) { |
| strncpy(ril_service_name, ril_service_name_base, MAX_SERVICE_NAME_LENGTH); |
| strncat(ril_service_name, clientId, MAX_SERVICE_NAME_LENGTH); |
| } |
| |
| if (rilLibPath == NULL) { |
| if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) { |
| // No lib sepcified on the command line, and nothing set in props. |
| // Assume "no-ril" case. |
| goto done; |
| } else { |
| rilLibPath = libPath; |
| } |
| } |
| |
| dlHandle = dlopen(rilLibPath, RTLD_NOW); |
| |
| if (dlHandle == NULL) { |
| RLOGE("dlopen failed: %s", dlerror()); |
| exit(EXIT_FAILURE); |
| } |
| |
| RIL_startEventLoop(); |
| |
| rilInit = |
| (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **)) |
| dlsym(dlHandle, "RIL_Init"); |
| |
| if (rilInit == NULL) { |
| RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath); |
| exit(EXIT_FAILURE); |
| } |
| |
| dlerror(); // Clear any previous dlerror |
| rilUimInit = |
| (RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **)) |
| dlsym(dlHandle, "RIL_SAP_Init"); |
| err_str = dlerror(); |
| if (err_str) { |
| RLOGW("RIL_SAP_Init not defined or exported in %s: %s\n", rilLibPath, err_str); |
| } else if (!rilUimInit) { |
| RLOGW("RIL_SAP_Init defined as null in %s. SAP Not usable\n", rilLibPath); |
| } |
| |
| if (hasLibArgs) { |
| rilArgv = argv + i - 1; |
| argc = argc -i + 1; |
| } else { |
| static char * newArgv[MAX_LIB_ARGS]; |
| static char args[PROPERTY_VALUE_MAX]; |
| rilArgv = newArgv; |
| property_get(LIB_ARGS_PROPERTY, args, ""); |
| argc = make_argv(args, rilArgv); |
| } |
| |
| rilArgv[argc++] = "-c"; |
| rilArgv[argc++] = (char*)clientId; |
| RLOGD("RIL_Init argc = %d clientId = %s", argc, rilArgv[argc-1]); |
| |
| // Make sure there's a reasonable argv[0] |
| rilArgv[0] = argv[0]; |
| |
| funcs = rilInit(&s_rilEnv, argc, rilArgv); |
| RLOGD("RIL_Init rilInit completed"); |
| |
| RIL_register(funcs); |
| |
| RLOGD("RIL_Init RIL_register completed"); |
| |
| if (rilUimInit) { |
| RLOGD("RIL_register_socket started"); |
| RIL_register_socket(rilUimInit, RIL_SAP_SOCKET, argc, rilArgv); |
| } |
| |
| RLOGD("RIL_register_socket completed"); |
| |
| done: |
| |
| rilc_thread_pool(); |
| |
| RLOGD("RIL_Init starting sleep loop");*/ |
| // while (1) { |
| // // ALOGI("start autosuspend_enable:%d\n",(i++)); |
| // sleep(5); |
| |
| // } |
| } |