|  | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <errno.h> | 
 | #include <string.h> | 
 | #include <sys/types.h> | 
 | #include <sys/socket.h> | 
 | #include <sys/un.h> | 
 | #include <unistd.h> | 
 | #include <dlfcn.h> | 
 | #include <pthread.h> | 
 | #include <stdbool.h> | 
 | #include <time.h> | 
 |  | 
 | #define LOG_TAG "libautosuspend" | 
 |  | 
 | // #include <liblog/lynq_deflog.h> | 
 | #include <log/log.h> | 
 |  | 
 | #define SERVER_CMD_PATH "/tmp/autosuspend.cmd.server" | 
 | #define SERVER_DATA_PATH "/tmp/autosuspend.data.server" | 
 | // #define CLIENT_PATH "/tmp/autosuspend.client" | 
 |  | 
 |  | 
 | static int client_sock_fd; | 
 |  | 
 | static int client_data_sock_fd; | 
 |  | 
 | static bool libautosuspend_inited; | 
 |  | 
 | // static bool libautosuspend_enabled; | 
 |  | 
 | // static pthread_mutex_t get_feedback_mutex = PTHREAD_MUTEX_INITIALIZER; | 
 |  | 
 | // static pthread_cond_t get_feedback_cond = PTHREAD_COND_INITIALIZER; | 
 |  | 
 | static pthread_mutex_t client_fd_mutex = PTHREAD_MUTEX_INITIALIZER; | 
 |  | 
 | static pthread_mutex_t client_data_fd_mutex = PTHREAD_MUTEX_INITIALIZER; | 
 |  | 
 | static pthread_mutex_t feedback_got_mutex = PTHREAD_MUTEX_INITIALIZER; | 
 |  | 
 | static pthread_cond_t feedback_got_cond = PTHREAD_COND_INITIALIZER; | 
 |  | 
 | struct time_info_t | 
 | { | 
 |     long sleep_start_time; | 
 |     long wakeup_time; | 
 | }; | 
 |  | 
 | static struct time_info_t time_info_client;  | 
 |  | 
 | 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 -2; | 
 |         } | 
 |         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; | 
 | } | 
 |  | 
 | static int connect_to_server(int *cfd, char *client_path, char *server_path) | 
 | { | 
 |     int rc; | 
 |     struct sockaddr_un server_sockaddr;  | 
 |     struct sockaddr_un client_sockaddr;  | 
 |  | 
 |  | 
 |     ALOGI("Start bind and connect to the service.\n"); | 
 |  | 
 |     /**************************************/ | 
 |     /* Create a UNIX domain stream socket */ | 
 |     /**************************************/ | 
 |     *cfd = socket(AF_UNIX, SOCK_STREAM, 0); | 
 |     if (*cfd == -1) { | 
 |         ALOGI("SOCKET ERROR "); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     /***************************************/ | 
 |     /* Set up the UNIX sockaddr structure  */ | 
 |     /* by using AF_UNIX for the family and */ | 
 |     /* giving it a filepath to bind to.    */ | 
 |     /*                                     */ | 
 |     /* Unlink the file so the bind will    */ | 
 |     /* succeed, then bind to that file.    */ | 
 |     /***************************************/ | 
 |     client_sockaddr.sun_family = AF_UNIX;   | 
 |     strcpy(client_sockaddr.sun_path, client_path);  | 
 |      | 
 |     unlink(client_sockaddr.sun_path); | 
 |  | 
 |     rc = bind(*cfd, (struct sockaddr *) &client_sockaddr, sizeof(client_sockaddr)); | 
 |     if (rc == -1){ | 
 |         ALOGI("BIND ERROR "); | 
 |         Close(*cfd); | 
 |         return -1; | 
 |     } | 
 |          | 
 |     /***************************************/ | 
 |     /* Set up the UNIX sockaddr structure  */ | 
 |     /* for the server socket and connect   */ | 
 |     /* to it.                              */ | 
 |     /***************************************/ | 
 |     server_sockaddr.sun_family = AF_UNIX; | 
 |      | 
 |     strcpy(server_sockaddr.sun_path, server_path); | 
 |  | 
 |     rc = connect(*cfd, (struct sockaddr *) &server_sockaddr, sizeof(client_sockaddr)); | 
 |     if(rc == -1){ | 
 |         ALOGI("CONNECT ERROR "); | 
 |         Close(*cfd); | 
 |         return -3; | 
 |     } | 
 |  | 
 |     return 0; | 
 |      | 
 | } | 
 |  | 
 | static void *deal_get_feedback(void *sockfd) | 
 | { | 
 |     int rc; | 
 |  | 
 |     int client_sock = *((int *)sockfd); | 
 |  | 
 |     // pthread_mutex_lock(&feedback_got_mutex); | 
 |      | 
 |     while (1) | 
 |     { | 
 |         // ALOGI("deal_get_feedback thread wait.\n"); | 
 |  | 
 |         // pthread_cond_wait(&get_feedback_cond,&get_feedback_mutex); | 
 |  | 
 |         ALOGI("start get feedback from the service.\n"); | 
 |  | 
 |         pthread_mutex_lock(&feedback_got_mutex); | 
 |  | 
 |         memset(&time_info_client,0,sizeof(struct time_info_t)); | 
 |  | 
 |         rc = Read(client_sock,&time_info_client,sizeof(struct time_info_t)); | 
 |         if(rc == -1) | 
 |         {            | 
 |             ALOGI("client read wakeup_feedback struct fail.\n"); | 
 |             Close(client_sock); | 
 |             pthread_mutex_unlock(&feedback_got_mutex); | 
 |             break ; | 
 |         } | 
 |         else if(rc == -2) | 
 |         { | 
 |             ALOGI("client read wakeup_feedback struct timeout.\n"); | 
 |             pthread_mutex_unlock(&feedback_got_mutex); | 
 |             continue; | 
 |         } | 
 |  | 
 |         ALOGI("system sleep_start timestamps : %ld ms\n",time_info_client.sleep_start_time); | 
 |         ALOGI("system wakeup timestamps : %ld ms\n",time_info_client.wakeup_time); | 
 |  | 
 |         // pthread_cond_broadcast(&feedback_got_cond); | 
 |  | 
 |         pthread_mutex_unlock(&feedback_got_mutex); | 
 |  | 
 |         usleep(10000);  //给libautosuspend_get_feedback函数时间进入wait,不可删除,但可以减少 | 
 |  | 
 |         pthread_cond_broadcast(&feedback_got_cond); | 
 |  | 
 |         usleep(10000); //希望多给libautosuspend_get_feedback函数拿到锁的机会,不可删除,但可以减少 | 
 |          | 
 |     } | 
 |      | 
 | } | 
 |  | 
 |  | 
 | static int libautosuspend_init() | 
 | { | 
 |     if (libautosuspend_inited) | 
 |     { | 
 |         return 0; | 
 |     } | 
 |  | 
 |     ALOGI("Start libautosuspend_init.\n"); | 
 |  | 
 |     char client_cmd_path[40]; | 
 |     char client_data_path[40]; | 
 |  | 
 |  | 
 |     sprintf(client_cmd_path,"/tmp/autosuspend.%d.cmd.client",(int)getpid()); | 
 |     sprintf(client_data_path,"/tmp/autosuspend.%d.data.client",(int)getpid()); | 
 |  | 
 |     pthread_mutex_lock(&client_fd_mutex); | 
 |  | 
 |     if(connect_to_server(&client_sock_fd,client_cmd_path,SERVER_CMD_PATH) < 0) | 
 |     { | 
 |         ALOGI("cmd channel connect error.\n"); | 
 |         pthread_mutex_unlock(&client_fd_mutex); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     if(connect_to_server(&client_data_sock_fd,client_data_path,SERVER_DATA_PATH) < 0) | 
 |     { | 
 |         ALOGI("data channel connect error.\n"); | 
 |         pthread_mutex_unlock(&client_fd_mutex); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     pthread_t feedback_tid; | 
 |     pthread_create(&feedback_tid,NULL,deal_get_feedback,(void*)&client_data_sock_fd); | 
 |     pthread_detach(feedback_tid); | 
 |  | 
 |  | 
 |     libautosuspend_inited = true; | 
 |  | 
 |     pthread_mutex_unlock(&client_fd_mutex); | 
 |      | 
 |     return 0; | 
 |      | 
 | } | 
 |  | 
 | static int send_cmd(char * value,int len) | 
 | { | 
 |     int rc; | 
 |  | 
 |     if(value == NULL) | 
 |     { | 
 |        return -1; | 
 |     } | 
 |      | 
 |     /************************************/ | 
 |     /* Copy the data to the buffer and  */ | 
 |     /* send it to the server socket.    */ | 
 |     /************************************/ | 
 |     // strcpy(buf, DATA); | 
 |  | 
 |     ALOGI("Sending data...\n"); | 
 |     rc = send(client_sock_fd, value, len, 0); | 
 |     if (rc == -1) { | 
 |         ALOGI("SEND ERROR "); | 
 |         Close(client_sock_fd); | 
 |         return -2; | 
 |     }    | 
 |     else { | 
 |         ALOGI("Data sent: %s\n",value); | 
 |     } | 
 |  | 
 |     // Close(client_sock); | 
 |  | 
 |     return rc; | 
 |  | 
 | } | 
 |  | 
 | int lynq_autosleep_enable(void) | 
 | { | 
 |     char value[15]="enable"; | 
 |     char res[15]; | 
 |  | 
 |     if(libautosuspend_init() != 0) | 
 |     { | 
 |         return -1; | 
 |     } | 
 |  | 
 |     // if(libautosuspend_enabled) | 
 |     // { | 
 |     //     return 0; | 
 |     // } | 
 |  | 
 |     pthread_mutex_lock(&client_fd_mutex); | 
 |  | 
 |     int rc = send_cmd(value,strlen(value)); | 
 |     if(rc < 0) | 
 |     { | 
 |         ALOGI("libautosuspend send enable cmd fail.\n"); | 
 |         pthread_mutex_unlock(&client_fd_mutex); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     // if(Read(client_sock_fd,res,sizeof(res)) <= 0) | 
 |     // { | 
 |     //     ALOGI("libautosuspend get respond fail.\n"); | 
 |     //     pthread_mutex_unlock(&client_fd_mutex); | 
 |     //     return -1; | 
 |     // } | 
 |  | 
 |     // ALOGI("libautosuspend get respond : %s.\n",res); | 
 |  | 
 |     // if(strcmp(res,"enabled") != 0) | 
 |     // { | 
 |     //     pthread_mutex_unlock(&client_fd_mutex); | 
 |     //     return -1; | 
 |     // } | 
 |  | 
 |     // libautosuspend_enabled = true; | 
 |  | 
 |     pthread_mutex_unlock(&client_fd_mutex); | 
 |  | 
 |     return 1; | 
 |    | 
 | } | 
 |  | 
 | int lynq_autosleep_disable(void) | 
 | { | 
 |     char value[15]="disable"; | 
 |     char res[15]; | 
 |  | 
 |     if(libautosuspend_init() != 0) | 
 |     { | 
 |         return -1; | 
 |     } | 
 |  | 
 |     // if(!libautosuspend_enabled) | 
 |     // { | 
 |     //     return 0; | 
 |     // } | 
 |  | 
 |     pthread_mutex_lock(&client_fd_mutex); | 
 |  | 
 |     int rc = send_cmd(value,strlen(value)); | 
 |     if(rc < 0) | 
 |     { | 
 |         ALOGI("libautosuspend send disable cmd fail.\n"); | 
 |         pthread_mutex_unlock(&client_fd_mutex); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     // if(Read(client_sock_fd,res,sizeof(res)) <= 0) | 
 |     // { | 
 |     //     ALOGI("libautosuspend get respond fail.\n"); | 
 |     //     pthread_mutex_unlock(&client_fd_mutex); | 
 |     //     return -1; | 
 |     // } | 
 |  | 
 |     // ALOGI("libautosuspend get respond : %s.\n",res); | 
 |  | 
 |     // if(strcmp(res,"disabled") != 0) | 
 |     // { | 
 |     //     pthread_mutex_unlock(&client_fd_mutex); | 
 |     //     return -1; | 
 |     // } | 
 |  | 
 |     // libautosuspend_enabled = false; | 
 |  | 
 |     pthread_mutex_unlock(&client_fd_mutex); | 
 |  | 
 |     return 1; | 
 |  | 
 | } | 
 |  | 
 |  | 
 |  | 
 | int libautosuspend_get_feedback(struct time_info_t *time_info) | 
 | { | 
 |     // char value[15]="feedback"; | 
 |     // char res[15];     | 
 |  | 
 |     // if(!libautosuspend_enabled) | 
 |     // { | 
 |     //     ALOGI("system autosuspend disabled, can not get wakeup feedback.\n"); | 
 |     //     return -1; | 
 |     // } | 
 |  | 
 |     ALOGI("start get feedback from the service.\n"); | 
 |  | 
 |     memset(time_info,0,sizeof(struct time_info_t)); | 
 |  | 
 |     // if(timeout == NULL) | 
 |     // { | 
 |     //     ALOGI("client set timeout for receiving wakeup_feedback: NULL.\n"); | 
 |     // } | 
 |     // else | 
 |     // { | 
 |     //     struct timeval recv_timeout = {(*timeout),0}; | 
 |     //     pthread_mutex_lock(&client_data_fd_mutex); | 
 |     //     if(setsockopt(client_data_sock_fd,SOL_SOCKET,SO_RCVTIMEO,(char*)&recv_timeout,sizeof(struct timeval)) == -1) | 
 |     //     { | 
 |     //         ALOGI("client set timeout for receiving wakeup_feedback: error.\n"); | 
 |     //         pthread_mutex_unlock(&client_data_fd_mutex); | 
 |     //         return -1; | 
 |     //     } | 
 |              | 
 |     //     ALOGI("client set timeout for receiving wakeup_feedback: %d s.\n",(*timeout)); | 
 |     //     pthread_mutex_unlock(&client_data_fd_mutex); | 
 |          | 
 |     // } | 
 |  | 
 |     // int rc = send_cmd(value,strlen(value)); | 
 |     // if(rc < 0) | 
 |     // { | 
 |     //     ALOGI("libautosuspend send feedback cmd fail.\n"); | 
 |     //     pthread_mutex_unlock(&client_fd_mutex); | 
 |     //     return -1; | 
 |     // } | 
 |  | 
 |     // if(Read(client_data_sock_fd,time_info,sizeof(struct time_info_t)) <= 0) | 
 |     // { | 
 |     //     ALOGI("libautosuspend_get_feedback fail.\n"); | 
 |     //     pthread_mutex_unlock(&client_fd_mutex); | 
 |     //     return -1; | 
 |     // } | 
 |  | 
 |  | 
 |     ALOGI("libautosuspend_get_feedback wait.\n"); | 
 |  | 
 |     pthread_mutex_lock(&feedback_got_mutex); | 
 |  | 
 |     pthread_cond_wait(&feedback_got_cond,&feedback_got_mutex); | 
 |  | 
 |     memcpy(time_info,&time_info_client,sizeof(struct time_info_t)); | 
 |  | 
 |     ALOGI("libautosuspend_get_feedback success.\n"); | 
 |  | 
 |     pthread_mutex_unlock(&feedback_got_mutex); | 
 |     // ALOGI("[client] system sleep_start timestamps : %ld ms\n",time_info.sleep_start_time); | 
 |     // ALOGI("[client] system wakeup timestamps : %ld ms\n",time_info.wakeup_time); | 
 |  | 
 |     return 0; | 
 |  | 
 | } | 
 |  | 
 |  | 
 | int lynq_wait_wakeup_event(long *sleep_start_time, long * wakeup_time) | 
 | { | 
 |    int *socket_timeout = NULL; | 
 |    struct time_info_t time_info; | 
 |    int ret = 0; | 
 |      | 
 |    memset(&time_info,0,sizeof(struct time_info_t)); | 
 |    if(sleep_start_time == NULL || wakeup_time == NULL ) | 
 |    { | 
 |       ALOGI("lynq_wait_wakeup_event input errors.\n"); | 
 | 	  return -1; | 
 |    } | 
 |    ret=libautosuspend_get_feedback(&time_info); | 
 |    if(ret == 0) | 
 |    { | 
 |      *sleep_start_time = time_info.sleep_start_time; | 
 | 	 *wakeup_time = time_info.wakeup_time; | 
 | 	 return 0; | 
 |    } | 
 |    else | 
 |    { | 
 |       return -1; | 
 |    } | 
 |     | 
 |  | 
 | } | 
 |  | 
 | // static void libautosuspend_get_feedback() | 
 | // {    | 
 | //     pthread_t feedback_tid; | 
 | //     pthread_create(&feedback_tid,NULL,deal_get_feedback,(void*)&client_sock); | 
 | //     pthread_detach(&feedback_tid); | 
 |  | 
 | //     return ; | 
 |      | 
 | // } | 
 |  | 
 |  | 
 |  |