blob: efa8f6dacf073a16e223660f1733d61400290491 [file] [log] [blame]
/*
* 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;
}