| /* |
| * Copyright Statement: |
| * |
| * This software/firmware and related documentation ("MediaTek Software") are |
| * protected under relevant copyright laws. The information contained herein is |
| * confidential and proprietary to MediaTek Inc. and/or its licensors. Without |
| * the prior written permission of MediaTek inc. and/or its licensors, any |
| * reproduction, modification, use or disclosure of MediaTek Software, and |
| * information contained herein, in whole or in part, shall be strictly |
| * prohibited. |
| * |
| * MediaTek Inc. (C) 2017. All rights reserved. |
| * |
| * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
| * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
| * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER |
| * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL |
| * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR |
| * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH |
| * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, |
| * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES |
| * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. |
| * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO |
| * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK |
| * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE |
| * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR |
| * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S |
| * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE |
| * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE |
| * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE |
| * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
| */ |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <sys/types.h> |
| #include <sys/un.h> |
| #include <log/log.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <string> |
| #include <vector> |
| #include <sys/time.h> |
| #include <sys/select.h> |
| #include <vector> |
| #include <deque> |
| #include <iterator> |
| #include <algorithm> |
| |
| #include "common.h" |
| #include "powerManager.h" |
| #include "util/utils.h" |
| #include "stateManager/stateManager.h" |
| #include <vendor-ril/telephony/ril.h> |
| |
| #undef DEMOAPP_SOCKET_NAME |
| #define DEMOAPP_SOCKET_NAME "/tmp/socket-demoapp" |
| #define SOCKET_BUF_SIZE 1024 |
| #define MAX_CLIENT_SIZE 30 |
| #undef LOG_TAG |
| #define LOG_TAG "DEMO_powermanager" |
| int cli_socket[MAX_CLIENT_SIZE]; |
| std::vector<int> keepalive_start; |
| std::vector<int> Keepalive_stop; |
| |
| //global variable |
| static pthread_mutex_t s_WakeupMutex = PTHREAD_MUTEX_INITIALIZER; |
| static pthread_cond_t s_WakeupCond = PTHREAD_COND_INITIALIZER; |
| //marco define |
| #define LIST_LOCK() pthread_mutex_lock(&s_WakeupMutex) |
| #define LIST_UNLOCK() pthread_mutex_unlock(&s_WakeupMutex) |
| #define WAITLIST() pthread_cond_wait(&s_WakeupCond,&s_WakeupMutex) |
| #define WAKEUPLIST() pthread_cond_signal(&s_WakeupCond) |
| #define WAKEUPREASONPATH "/sys/power/spm/wakeup_reason" |
| //#define WAKEUPSTATUS "/sys/power/suspend_status" |
| |
| static std::deque<std::string> wakeup_reasons; |
| |
| std::string read_wakeup_reason() { |
| if(access(WAKEUPREASONPATH, R_OK) == -1) { |
| RLOGD("read_wakeup_reason, %s cann't read(%s),just return", WAKEUPREASONPATH, strerror(errno)); |
| return ""; |
| } |
| |
| int fd; |
| fd = open(WAKEUPREASONPATH , O_RDONLY); |
| if(fd == -1) { |
| RLOGD("read_wakeup_reason, open %s fail(%s),just return", WAKEUPREASONPATH, strerror(errno)); |
| return ""; |
| } |
| |
| ssize_t len; |
| char buf[50]={0}; |
| std::string reason(""); |
| len = read(fd, buf,sizeof(buf) -1); |
| if(len == -1) { |
| RLOGD("read_wakeup_reason, read %s fail(%s),just return", WAKEUPREASONPATH, strerror(errno)); |
| reason=""; |
| goto fail; |
| } |
| RLOGD("read_wakeup_reason is %s", buf); |
| reason = buf; |
| fail: |
| close(fd); |
| return reason; |
| } |
| |
| void write_wakeup_reason(std::string reason) { |
| int fd; |
| ssize_t len; |
| if(reason.empty()) { |
| RLOGD("write_wakeup_reason is empty, just return"); |
| return; |
| } |
| std::string save = read_wakeup_reason(); |
| if(save == reason) { |
| RLOGD("write_wakeup_reason is same, just return"); |
| // return; //don't need return, handle initial reason equal to first write reason. |
| } |
| RLOGD("write_wakeup_reason: %s", reason.c_str()); |
| if(access(WAKEUPREASONPATH, W_OK) == -1) { |
| RLOGD("write_wakeup_reason, %s cann't write(%s), just return", WAKEUPREASONPATH, strerror(errno)); |
| return ; |
| } |
| fd = open(WAKEUPREASONPATH , O_WRONLY); |
| if(fd == -1) { |
| RLOGD("write_wakeup_reason, open %s fail(%s), just return", WAKEUPREASONPATH,strerror(errno)); |
| return ; |
| } |
| len = write(fd, reason.c_str(), reason.size()); |
| if(len == -1) { |
| RLOGD("write_wakeup_reason, write %s fail(%s)", WAKEUPREASONPATH,strerror(errno)); |
| } |
| close(fd); |
| } |
| |
| void *wakeup_reason_loop(void *param) |
| { |
| std::string reason(""); |
| RLOGD("wakeup_reason_loop start"); |
| |
| prctl(PR_SET_NAME,(unsigned long)"demo_wakeup_reason_loop"); |
| |
| LIST_LOCK(); |
| wakeup_reasons.clear(); |
| LIST_UNLOCK(); |
| |
| for(;;){ |
| |
| LIST_LOCK(); |
| if(wakeup_reasons.empty()) { //if blank list then wait |
| RLOGD("wakeup reason list is empty ,then wait!"); |
| while(wakeup_reasons.empty()){ |
| WAITLIST(); |
| } |
| } |
| reason = wakeup_reasons.front(); |
| wakeup_reasons.pop_front(); |
| LIST_UNLOCK(); |
| write_wakeup_reason(reason); |
| } |
| return 0; |
| } |
| |
| void handle_wakeup_reason(int requestCode) { |
| RLOGD("handle_wakeup_reason %s:", android::requestToString(requestCode)); |
| std::string reason(""); |
| switch (requestCode){ |
| //CCIF_CALL |
| case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: |
| case RIL_UNSOL_CALL_RING: |
| case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: |
| case RIL_UNSOL_RINGBACK_TONE: |
| case RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE: |
| case RIL_UNSOL_SRVCC_STATE_NOTIFY: |
| case RIL_UNSOL_ECONF_SRVCC_INDICATION: |
| case RIL_UNSOL_ECONF_RESULT_INDICATION: |
| case RIL_UNSOL_CRSS_NOTIFICATION: |
| case RIL_UNSOL_INCOMING_CALL_INDICATION: |
| case RIL_UNSOL_CALL_INFO_INDICATION: |
| case RIL_UNSOL_SUPP_SVC_NOTIFICATION: |
| { |
| reason = "CCIF_CALL"; |
| break; |
| } |
| //CCIF_NW |
| case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: |
| case RIL_UNSOL_NITZ_TIME_RECEIVED: |
| case RIL_UNSOL_SIGNAL_STRENGTH: |
| case RIL_UNSOL_RESTRICTED_STATE_CHANGED: |
| case RIL_UNSOL_CELL_INFO_LIST: |
| case RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED: |
| { |
| reason = "CCIF_NW"; |
| break; |
| } |
| //CCIF_Message |
| case RIL_UNSOL_RESPONSE_NEW_SMS: |
| case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: |
| case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: |
| case RIL_UNSOL_SIM_SMS_STORAGE_FULL: |
| case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: |
| case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: |
| case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: |
| case RIL_UNSOL_SMS_READY_NOTIFICATION: |
| case RIL_UNSOL_ON_USSD: |
| { |
| reason = "CCIF_MESSAGE"; |
| break; |
| } |
| //CCIF_Other |
| case RIL_UNSOL_DATA_CALL_LIST_CHANGED: |
| case RIL_UNSOL_ECALL_MSDHACK: |
| case RIL_UNSOL_SIM_REFRESH: |
| case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: |
| case RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED: |
| case RIL_UNSOL_STK_SESSION_END: |
| case RIL_UNSOL_STK_PROACTIVE_COMMAND: |
| case RIL_UNSOL_STK_EVENT_NOTIFY: |
| case RIL_UNSOL_STK_CALL_SETUP: |
| case RIL_UNSOL_STK_BIP_PROACTIVE_COMMAND: |
| case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: |
| case RIL_UNSOL_RIL_CONNECTED: |
| case RIL_UNSOL_RADIO_CAPABILITY: |
| { |
| reason = "CCIF_OTHER"; |
| break; |
| } |
| default: |
| RLOGD("handle_wakeup_reason no wakeup reason, just return"); |
| return; |
| } |
| if(reason.empty()) { |
| RLOGE("handle_wakeup_reason error , reason is empty, return"); |
| return; |
| } |
| LIST_LOCK(); |
| wakeup_reasons.push_back(reason); |
| WAKEUPLIST(); |
| LIST_UNLOCK(); |
| } |
| |
| int demo_open_socket(const char *path) |
| { |
| RLOGD("demo_open_socket"); |
| int sd; |
| int res; |
| struct sockaddr_un addr; |
| |
| sd = socket(AF_UNIX, SOCK_STREAM, 0); |
| if (sd < 0) { |
| RLOGE("socket error: %s", strerror(errno)); |
| return sd; |
| } |
| |
| if(remove(path) == -1 && errno != ENOENT) |
| { |
| RLOGD("remove-%s, remove error: %s", path, strerror(errno)); |
| } |
| |
| memset(&addr, 0, sizeof(struct sockaddr_un)); |
| addr.sun_family = AF_UNIX; |
| strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1); |
| |
| res = bind(sd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)); |
| if (res != 0) { |
| RLOGE("bind error: %s\n", strerror(errno)); |
| goto error; |
| } |
| |
| res = listen(sd, 8); |
| if (res != 0) { |
| RLOGE("listen error: %s\n", strerror(errno)); |
| goto error; |
| } |
| return sd; |
| error: |
| if (sd >=0) |
| close(sd); |
| return -1; |
| } |
| |
| int send_data(int sockfd, const char *buf, int len) { |
| int ret = 0; |
| int cur_pos = 0; |
| |
| if (sockfd <= 0) |
| return 0; |
| |
| while(cur_pos < len) { |
| ret = send(sockfd, &buf[cur_pos], len - cur_pos, MSG_DONTWAIT); |
| if (ret == len - cur_pos) |
| break; |
| |
| if (ret <= 0) { |
| RLOGE("SOCKET ERROR errno:%d,%s", errno, strerror(errno)); |
| if (errno == EAGAIN || errno == EINTR) |
| { |
| RLOGD("send to internet buffer full, wait(10ms)"); |
| usleep(10000); |
| continue; |
| } |
| if (errno == ECONNRESET || errno == EPIPE) |
| { |
| sockfd = -1; |
| RLOGD("buffer client connect is reset"); |
| } |
| break; |
| } else |
| cur_pos += ret; |
| } |
| |
| return ret; |
| } |
| |
| void sendSmsMsg(RIL_SOCKET_ID soc_id) |
| { |
| char *msg = "sms_on"; |
| for (int i = 0 ; i < MAX_CLIENT_SIZE; i++) { |
| if(cli_socket[i] > 0 ) { |
| auto it_start = std::find(keepalive_start.begin(), keepalive_start.end(), cli_socket[i]); |
| auto it_stop = std::find(Keepalive_stop.begin(), Keepalive_stop.end(), cli_socket[i]); |
| if(it_start == std::end(keepalive_start) && it_stop == std::end(Keepalive_stop)) { |
| RLOGD("sendSmsMsg(%d): %s", cli_socket[i], msg); |
| send_data(cli_socket[i], msg, strlen(msg)); |
| } |
| } |
| } |
| } |
| |
| void sendCallMsg(bool call_on) |
| { |
| char* on = "call_on"; |
| char* off = "call_off"; |
| char *msg = call_on ? on : off; |
| for (int i = 0 ; i < MAX_CLIENT_SIZE; i++) { |
| if(cli_socket[i] > 0 ) { |
| auto it_start = std::find(keepalive_start.begin(), keepalive_start.end(), cli_socket[i]); |
| auto it_stop = std::find(Keepalive_stop.begin(), Keepalive_stop.end(), cli_socket[i]); |
| if(it_start == std::end(keepalive_start) && it_stop == std::end(Keepalive_stop)) { |
| RLOGD("sendSmsMsg(%d): %s", cli_socket[i], msg); |
| send_data(cli_socket[i], msg, strlen(msg)); |
| } |
| } |
| } |
| } |
| |
| void sendKeepAlive(const char* msg) |
| { |
| std::string str(msg); |
| if (str.find("RIL_REQUEST_START_KEEPALIVE_PRO") != std::string::npos) { |
| for (auto it : keepalive_start) { |
| RLOGD("sendKeepAlive response(RIL_REQUEST_START_KEEPALIVE_PRO(%d)): %s",it, msg); |
| send_data(it, msg, strlen(msg)); |
| } |
| } |
| |
| if (str.find("RIL_REQUEST_STOP_KEEPALIVE_PRO") != std::string::npos) { |
| for (auto it : Keepalive_stop) { |
| RLOGD("sendKeepAlive response(RIL_REQUEST_STOP_KEEPALIVE_PRO(%d)): %s", it, msg); |
| send_data(it, msg, strlen(msg)); |
| } |
| } |
| |
| if (str.find("RIL_UNSOL_KEEPALIVE_STATUS_PRO") != std::string::npos) { |
| for (auto it : keepalive_start) { |
| RLOGD("sendKeepAlive notify((start)RIL_UNSOL_KEEPALIVE_STATUS_PRO(%d)): %s", it, msg); |
| send_data(it, msg, strlen(msg)); |
| } |
| for (auto it : Keepalive_stop) { |
| RLOGD("sendKeepAlive notify((stop)RIL_UNSOL_KEEPALIVE_STATUS_PRO(%d)): %s", it, msg); |
| send_data(it, msg, strlen(msg)); |
| } |
| } |
| } |
| |
| #define SOCKET_ZERO 0 |
| #define SOCKET_SUCC 1 |
| #define SOCKET_FAIL -1 |
| |
| void dispatch_cmd(int fd, char* msg) { |
| RLOGD("dispatch_cmd: %s", msg); |
| std::vector<std::string> v; |
| utils::tokenize(std::string(msg),',',v); |
| int i = 0; |
| for(auto s: v) { |
| RLOGD("%d:%s",i, s.c_str()); |
| i++; |
| } |
| if(v.size() != 10 && v.size() != 2) { |
| RLOGE("transfer parameters num is wrong: %d", v.size()); |
| return ; |
| } |
| int id = get_default_sim_data(); |
| if(v[0] == std::string("RIL_REQUEST_START_KEEPALIVE_PRO")) { |
| keepalive_start.push_back(fd); |
| RLOGD("[SIM%d]start keepalive", id); |
| RequestInfo *info = creatRILInfoAndInit(RIL_REQUEST_START_KEEPALIVE_PRO, OTHER, (RIL_SOCKET_ID)id); |
| char* argv[10] = {0}; |
| for(int i=0; i< v.size() && i < 10; i++){ |
| argv[i] = const_cast<char*>(v[i].c_str()); |
| } |
| startKeepAlivePro(v.size(), argv, (RIL_SOCKET_ID)id, info); |
| } else if(v[0] == std::string("RIL_REQUEST_STOP_KEEPALIVE_PRO")) { |
| Keepalive_stop.push_back(fd); |
| RLOGD("[SIM%d]stop keepalive", id); |
| RequestInfo *info = creatRILInfoAndInit(RIL_REQUEST_STOP_KEEPALIVE_PRO, OTHER, (RIL_SOCKET_ID)id); |
| char* argv[2] = {0}; |
| for(int i=0; i< v.size() && i < 2; i++){ |
| argv[i] = const_cast<char*>(v[i].c_str()); |
| } |
| stopKeepAlivePro(v.size(), argv, (RIL_SOCKET_ID)id, info); |
| } else { |
| RLOGD("dispatch_cmd(%s) error", v[0].c_str()); |
| } |
| } |
| |
| void eraseSocket(std::vector<int> &v, int sd) { |
| auto it = std::find(v.begin(), v.end(), sd); |
| if (it != std::end(v)) { |
| v.erase(it); |
| } |
| } |
| |
| void *StartPMSocket(void *param) |
| { |
| RLOGD("StartPMSocket start"); |
| char buf[SOCKET_BUF_SIZE] = {0}; |
| int max_fd; |
| fd_set readfds; |
| for (int i=0; i < MAX_CLIENT_SIZE; i++) { |
| cli_socket[i] = 0; |
| } |
| int ssd = -1; |
| struct sockaddr_un addr; |
| socklen_t socke_len; |
| |
| ssd = demo_open_socket(DEMOAPP_SOCKET_NAME); |
| if(ssd < 0) |
| { |
| RLOGE("ssd < 0, just return"); |
| return NULL; |
| } |
| |
| while (true) { |
| FD_ZERO(&readfds); |
| FD_SET(ssd, &readfds); |
| max_fd = ssd; |
| for(int i = 0; i < MAX_CLIENT_SIZE; i++) { |
| int sd = cli_socket[i]; |
| if(sd > 0) { |
| FD_SET(sd, &readfds); |
| } |
| if(sd > max_fd) { |
| max_fd = sd; |
| } |
| } |
| int act_fd_num = select(max_fd +1, &readfds, NULL, NULL, NULL); |
| if(act_fd_num < 0 && (errno != EINTR)) { |
| RLOGE("select error"); |
| } |
| if(FD_ISSET(ssd, &readfds)) { |
| int cli_soc = accept(ssd, (struct sockaddr*)&addr, &socke_len); |
| if (cli_soc < 0) |
| { |
| RLOGE("accept error: %s", strerror(errno)); |
| close(cli_soc); |
| return NULL; |
| } |
| RLOGD("Accept a client , client id is %d", cli_soc); |
| //TBD send sometings. |
| for(int i = 0; i < MAX_CLIENT_SIZE; i++) { |
| if(cli_socket[i] == 0) { |
| cli_socket[i] = cli_soc; |
| RLOGD("add new socket %d", cli_soc); |
| break; |
| } |
| } |
| } |
| for(int i = 0; i < MAX_CLIENT_SIZE; i++) { |
| int sd = cli_socket[i]; |
| if(FD_ISSET(sd, &readfds)) { |
| memset(buf, 0, sizeof(buf)); |
| int ret = recv(sd, buf,SOCKET_BUF_SIZE, 0); |
| if (ret < 0) { |
| RLOGE("data_recv select error, ret=%d, error=%s(%d),fd=%d", ret, strerror(errno), errno, sd); |
| } else if (ret == SOCKET_ZERO) { |
| RLOGE("data_recv recv error, maybe client socket closed, ret=%d, error=%s(%d),fd=%d", ret, strerror(errno), errno, sd); |
| close(sd); |
| cli_socket[i] = 0; |
| eraseSocket(keepalive_start,sd); |
| eraseSocket(Keepalive_stop,sd); |
| } else { |
| buf[ret] = '\0'; |
| dispatch_cmd(sd, buf); |
| } |
| } |
| } |
| } |
| RLOGD("start PowerManager Done"); |
| return 0; |
| } |