Introduction of the new SAP-UIM socket

Added new socket connection for communication between the SAP module
in Telephony and User Identity Module with DSDA support.

New classes added are:

RilSocket
---------
Base class(virtual) for any type of socket. Has listen
and commands callbacks similar to that of the existing
telephony->rild socket.

RilSapSocket
------------
Derived class for socket for communication between BT SAP
and the sim module in the modem. It initialises
socket, calls Sap_Uim_Init to get the handles and
starts the socket thread.

rilSocketQueue
--------------
Queue for managing socket requests.

Change-Id: I8828173941d6ae76f1f9cc0d567efaf41a77d175
tirimbino
Dheeraj Shetty 10 years ago committed by Ethan Chen
parent 6187ef8378
commit cc231015f2
  1. 16
      ril/libril/Android.mk
  2. 457
      ril/libril/RilSapSocket.cpp
  3. 262
      ril/libril/RilSapSocket.h
  4. 177
      ril/libril/RilSocket.cpp
  5. 270
      ril/libril/RilSocket.h
  6. 142
      ril/libril/ril.cpp
  7. 167
      ril/libril/rilSocketQueue.h
  8. 48
      ril/libril/ril_ex.h

@ -7,7 +7,9 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES:= \
ril.cpp \ ril.cpp \
ril_event.cpp ril_event.cpp\
RilSocket.cpp \
RilSapSocket.cpp \
LOCAL_SHARED_LIBRARIES := \ LOCAL_SHARED_LIBRARIES := \
liblog \ liblog \
@ -15,7 +17,10 @@ LOCAL_SHARED_LIBRARIES := \
libbinder \ libbinder \
libcutils \ libcutils \
libhardware_legacy \ libhardware_legacy \
librilutils librilutils \
LOCAL_STATIC_LIBRARIES := \
libnanopb-c-2.8.0-enable_malloc \
ifneq ($(filter xmm6262 xmm6360,$(BOARD_MODEM_TYPE)),) ifneq ($(filter xmm6262 xmm6360,$(BOARD_MODEM_TYPE)),)
LOCAL_CFLAGS := -DMODEM_TYPE_XMM6262 LOCAL_CFLAGS := -DMODEM_TYPE_XMM6262
@ -30,10 +35,15 @@ ifeq ($(BOARD_MODEM_TYPE),m7450)
LOCAL_CFLAGS := -DMODEM_TYPE_M7450 LOCAL_CFLAGS := -DMODEM_TYPE_M7450
endif endif
LOCAL_C_INCLUDES += $(TARGET_OUT_HEADER)/librilutils
LOCAL_C_INCLUDES += external/nanopb-c
LOCAL_MODULE:= libril LOCAL_MODULE:= libril
include $(BUILD_SHARED_LIBRARY) LOCAL_COPY_HEADERS_TO := libril
LOCAL_COPY_HEADERS := ril_ex.h
include $(BUILD_SHARED_LIBRARY)
# For RdoServD which needs a static library # For RdoServD which needs a static library
# ========================================= # =========================================

@ -0,0 +1,457 @@
/*
* Copyright (C) 2014 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.
*/
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#define RIL_SHLIB
#include "telephony/ril.h"
#include "RilSapSocket.h"
#include "pb_decode.h"
#include "pb_encode.h"
#define LOG_TAG "RIL_UIM_SOCKET"
#include <utils/Log.h>
#include <arpa/inet.h>
RilSapSocket::RilSapSocketList *head;
void ril_sap_on_request_complete (
RIL_Token t, RIL_Errno e,
void *response, size_t responselen
);
void ril_sap_on_unsolicited_response (
int unsolResponse, const void *data,
size_t datalen
);
extern "C" void
RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
const struct timeval *relativeTime);
struct RIL_Env RilSapSocket::uimRilEnv = {
.OnRequestComplete = RilSapSocket::sOnRequestComplete,
.OnUnsolicitedResponse = RilSapSocket::sOnUnsolicitedResponse,
.RequestTimedCallback = RIL_requestTimedCallback
};
void RilSapSocket::sOnRequestComplete (RIL_Token t,
RIL_Errno e,
void *response,
size_t responselen) {
RilSapSocket *sap_socket;
SapSocketRequest *request = (SapSocketRequest*) t;
RLOGD("Socket id:%d", request->socketId);
sap_socket = getSocketById(request->socketId);
if (sap_socket) {
sap_socket->onRequestComplete(t,e,response,responselen);
} else {
RLOGE("Invalid socket id");
free(request->curr);
free(request);
}
}
#if defined(ANDROID_MULTI_SIM)
void RilSapSocket::sOnUnsolicitedResponse(int unsolResponse,
const void *data,
size_t datalen,
RIL_SOCKET_ID socketId) {
RilSapSocket *sap_socket = getSocketById(socketId);
if (sap_socket) {
sap_socket->onUnsolicitedResponse(unsolResponse, (void *)data, datalen);
}
}
#else
void RilSapSocket::sOnUnsolicitedResponse(int unsolResponse,
const void *data,
size_t datalen) {
RilSapSocket *sap_socket = getSocketById(RIL_SOCKET_1);
sap_socket->onUnsolicitedResponse(unsolResponse, (void *)data, datalen);
}
#endif
void RilSapSocket::printList() {
RilSapSocketList *current = head;
RLOGD("Printing socket list");
while(NULL != current) {
RLOGD("SocketName:%s",current->socket->name);
RLOGD("Socket id:%d",current->socket->id);
current = current->next;
}
}
RilSapSocket *RilSapSocket::getSocketById(RIL_SOCKET_ID socketId) {
RilSapSocket *sap_socket;
RilSapSocketList *current = head;
RLOGD("Entered getSocketById");
printList();
while(NULL != current) {
if(socketId == current->socket->id) {
sap_socket = current->socket;
return sap_socket;
}
current = current->next;
}
return NULL;
}
void RilSapSocket::initSapSocket(const char *socketName,
RIL_RadioFunctions *uimFuncs) {
if (strcmp(socketName, "sap_uim_socket1") == 0) {
if(!SocketExists(socketName)) {
addSocketToList(socketName, RIL_SOCKET_1, uimFuncs);
}
}
#if (SIM_COUNT >= 2)
if (strcmp(socketName, "sap_uim_socket2") == 0) {
if(!SocketExists(socketName)) {
addSocketToList(socketName, RIL_SOCKET_2, uimFuncs);
}
}
#endif
#if (SIM_COUNT >= 3)
if (strcmp(socketName, "sap_uim_socket3") == 0) {
if(!SocketExists(socketName)) {
addSocketToList(socketName, RIL_SOCKET_3, uimFuncs);
}
}
#endif
#if (SIM_COUNT >= 4)
if (strcmp(socketName, "sap_uim_socket4") == 0) {
if(!SocketExists(socketName)) {
addSocketToList(socketName, RIL_SOCKET_4, uimFuncs);
}
}
#endif
}
void RilSapSocket::addSocketToList(const char *socketName, RIL_SOCKET_ID socketid,
RIL_RadioFunctions *uimFuncs) {
RilSapSocket* socket = NULL;
RilSapSocketList* listItem = (RilSapSocketList*)malloc(sizeof(RilSapSocketList));
RilSapSocketList *current;
if(!SocketExists(socketName)) {
socket = new RilSapSocket(socketName, socketid, uimFuncs);
listItem->socket = socket;
listItem->next = NULL;
RLOGD("Adding socket with id: %d", socket->id);
if(NULL == head) {
head = listItem;
head->next = NULL;
}
else {
current = head;
while(NULL != current->next) {
current = current->next;
}
current->next = listItem;
}
socket->socketInit();
}
}
bool RilSapSocket::SocketExists(const char *socketName) {
RilSapSocketList* current = head;
while(NULL != current) {
if(strcmp(current->socket->name, socketName) == 0) {
return true;
}
current = current->next;
}
return false;
}
void* RilSapSocket::processRequestsLoop(void) {
SapSocketRequest *req = (SapSocketRequest*)malloc(sizeof(SapSocketRequest));
RLOGI("UIM_SOCKET:Request loop started");
while(true) {
req = dispatchQueue.dequeue();
RLOGI("New request from the dispatch Queue");
if (req != NULL) {
processRequest(req->curr);
free(req);
} else {
RLOGE("Fetched null buffer from queue!");
}
}
return NULL;
}
RilSapSocket::RilSapSocket(const char *socketName,
RIL_SOCKET_ID socketId,
RIL_RadioFunctions *inputUimFuncs):
RilSocket(socketName, socketId) {
if (inputUimFuncs) {
uimFuncs = inputUimFuncs;
}
}
int RilSapSocket::processRequest(MsgHeader *request) {
dispatchRequest(request);
return 0;
}
#define BYTES_PER_LINE 16
#define NIBBLE_TO_HEX(n) ({ \
uint8_t __n = (uint8_t) n & 0x0f; \
__nibble >= 10 ? 'A' + __n - 10: '0' + __n; \
})
#define HEX_HIGH(b) ({ \
uint8_t __b = (uint8_t) b; \
uint8_t __nibble = (__b >> 4) & 0x0f; \
NIBBLE_TO_HEX(__nibble); \
})
#define HEX_LOW(b) ({ \
uint8_t __b = (uint8_t) b; \
uint8_t __nibble = __b & 0x0f; \
NIBBLE_TO_HEX(__nibble); \
})
void log_hex(const char *who, const uint8_t *buffer, int length) {
char out[80];
int source = 0;
int dest = 0;
int dest_len = sizeof(out);
int per_line = 0;
do {
dest += sprintf(out, "%8.8s [%8.8x] ", who, source);
for(; source < length && dest_len - dest > 3 && per_line < BYTES_PER_LINE; source++,
per_line ++) {
out[dest++] = HEX_HIGH(buffer[source]);
out[dest++] = HEX_LOW(buffer[source]);
out[dest++] = ' ';
}
if (dest < dest_len && (per_line == BYTES_PER_LINE || source >= length)) {
out[dest++] = 0;
per_line = 0;
dest = 0;
RLOGD("%s\n", out);
}
} while(source < length && dest < dest_len);
}
void RilSapSocket::dispatchRequest(MsgHeader *req) {
SapSocketRequest* currRequest=(SapSocketRequest*)malloc(sizeof(SapSocketRequest));
currRequest->token = req->token;
currRequest->curr = req;
currRequest->p_next = NULL;
currRequest->socketId = id;
pendingResponseQueue.enqueue(currRequest);
if (uimFuncs) {
RLOGI("[%d] > SAP REQUEST type: %d. id: %d. error: %d",
req->token,
req->type,
req->id,
req->error );
#if defined(ANDROID_MULTI_SIM)
uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest, id);
#else
uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest);
#endif
}
}
void RilSapSocket::onRequestComplete(RIL_Token t, RIL_Errno e, void *response,
size_t response_len) {
SapSocketRequest* request= (SapSocketRequest*)t;
MsgHeader *hdr = request->curr;
pb_bytes_array_t *payload = (pb_bytes_array_t *)
calloc(1,sizeof(pb_bytes_array_t) + response_len);
if (hdr && payload) {
memcpy(payload->bytes, response, response_len);
payload->size = response_len;
hdr->payload = payload;
hdr->type = MsgType_RESPONSE;
hdr->error = (Error) e;
RLOGE("Token:%d, MessageId:%d", hdr->token, hdr->id);
if(!pendingResponseQueue.checkAndDequeue(hdr->id, hdr->token)) {
RLOGE("Token:%d, MessageId:%d", hdr->token, hdr->id);
RLOGE ("RilSapSocket::onRequestComplete: invalid Token or Message Id");
return;
}
sendResponse(hdr);
free(hdr);
}
}
void RilSapSocket::sendResponse(MsgHeader* hdr) {
size_t encoded_size = 0;
uint32_t written_size;
size_t buffer_size = 0;
pb_ostream_t ostream;
bool success = false;
pthread_mutex_lock(&write_lock);
if ((success = pb_get_encoded_size(&encoded_size, MsgHeader_fields,
hdr)) && encoded_size <= INT32_MAX && commandFd != -1) {
buffer_size = encoded_size + sizeof(uint32_t);
uint8_t buffer[buffer_size];
written_size = htonl((uint32_t) encoded_size);
ostream = pb_ostream_from_buffer(buffer, buffer_size);
pb_write(&ostream, (uint8_t *)&written_size, sizeof(written_size));
success = pb_encode(&ostream, MsgHeader_fields, hdr);
if (success) {
RLOGD("Size: %d (0x%x) Size as written: 0x%x", encoded_size, encoded_size,
written_size);
log_hex("onRequestComplete", &buffer[sizeof(written_size)], encoded_size);
RLOGI("[%d] < SAP RESPONSE type: %d. id: %d. error: %d",
hdr->token, hdr->type, hdr->id,hdr->error );
if ( 0 != blockingWrite_helper(commandFd, buffer, buffer_size)) {
RLOGE("Error %d while writing to fd", errno);
} else {
RLOGD("Write successful");
}
} else {
RLOGE("Error while encoding response of type %d id %d buffer_size: %d: %s.",
hdr->type, hdr->id, buffer_size, PB_GET_ERROR(&ostream));
}
} else {
RLOGE("Not sending response type %d: encoded_size: %u. commandFd: %d. encoded size result: %d",
hdr->type, encoded_size, commandFd, success);
}
pthread_mutex_unlock(&write_lock);
}
void RilSapSocket::onUnsolicitedResponse(int unsolResponse, void *data, size_t datalen) {
MsgHeader *hdr = new MsgHeader;
pb_bytes_array_t *payload = (pb_bytes_array_t *)
calloc(1, sizeof(pb_bytes_array_t) + datalen);
if (hdr && payload) {
memcpy(payload->bytes, data, datalen);
payload->size = datalen;
hdr->payload = payload;
hdr->type = MsgType_UNSOL_RESPONSE;
hdr->id = (MsgId)unsolResponse;
hdr->error = Error_RIL_E_SUCCESS;
sendResponse(hdr);
delete hdr;
}
}
void RilSapSocket::pushRecord(void *p_record, size_t recordlen) {
int ret;
SapSocketRequest *recv = (SapSocketRequest*)malloc(sizeof(SapSocketRequest));
MsgHeader *reqHeader;
pb_istream_t stream;
stream = pb_istream_from_buffer((uint8_t *)p_record, recordlen);
reqHeader = (MsgHeader *)malloc(sizeof (MsgHeader));
memset(reqHeader, 0, sizeof(MsgHeader));
log_hex("BtSapTest-Payload", (const uint8_t*)p_record, recordlen);
if (!pb_decode(&stream, MsgHeader_fields, reqHeader) ) {
RLOGE("Error decoding protobuf buffer : %s", PB_GET_ERROR(&stream));
} else {
recv->token = reqHeader->token;
recv->curr = reqHeader;
recv->socketId = id;
dispatchQueue.enqueue(recv);
}
}
void RilSapSocket::sendDisconnect() {
MsgHeader *hdr = new MsgHeader;
pb_bytes_array_t *payload ;
size_t encoded_size = 0;
uint32_t written_size;
size_t buffer_size = 0;
pb_ostream_t ostream;
bool success = false;
ssize_t written_bytes;
RIL_SIM_SAP_DISCONNECT_REQ disconnectReq;
if ((success = pb_get_encoded_size(&encoded_size, RIL_SIM_SAP_DISCONNECT_REQ_fields,
&disconnectReq)) && encoded_size <= INT32_MAX) {
buffer_size = encoded_size + sizeof(uint32_t);
uint8_t buffer[buffer_size];
written_size = htonl((uint32_t) encoded_size);
ostream = pb_ostream_from_buffer(buffer, buffer_size);
pb_write(&ostream, (uint8_t *)&written_size, sizeof(written_size));
success = pb_encode(&ostream, RIL_SIM_SAP_DISCONNECT_REQ_fields, buffer);
if(success) {
pb_bytes_array_t *payload = (pb_bytes_array_t *)
calloc(1,sizeof(pb_bytes_array_t) + written_size);
memcpy(payload->bytes, buffer, written_size);
payload->size = written_size;
hdr->payload = payload;
hdr->type = MsgType_REQUEST;
hdr->id = MsgId_RIL_SIM_SAP_DISCONNECT;
hdr->error = Error_RIL_E_SUCCESS;
dispatchDisconnect(hdr);
}
else {
RLOGE("Encode failed in send disconnect!");
delete hdr;
free(payload);
}
}
}
void RilSapSocket::dispatchDisconnect(MsgHeader *req) {
SapSocketRequest* currRequest=(SapSocketRequest*)malloc(sizeof(SapSocketRequest));
currRequest->token = -1;
currRequest->curr = req;
currRequest->p_next = NULL;
currRequest->socketId = (RIL_SOCKET_ID)99;
RLOGD("Sending disconnect on command close!");
#if defined(ANDROID_MULTI_SIM)
uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest, id);
#else
uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest);
#endif
}
void RilSapSocket::onCommandsSocketClosed() {
sendDisconnect();
RLOGE("Socket command closed");
}

@ -0,0 +1,262 @@
/*
* Copyright (C) 2014 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.
*/
#ifndef RIL_UIM_SOCKET_H_INCLUDED
#define RIL_UIM_SOCKET_H_INCLUDED
#define RIL_SHLIB
#include "telephony/ril.h"
#include "RilSocket.h"
#include <hardware/ril/librilutils/proto/sap-api.pb.h>
/**
* RilSapSocket is a derived class, derived from the RilSocket abstract
* class, representing sockets for communication between bluetooth SAP module and
* the ril daemon.
* <p>
* This class performs the following functions :
* <ul>
* <li>Initialize the socket.
* <li>Process the requests coming on the socket.
* <li>Provide handlers for Unsolicited and request responses.
* <li>Request and pending response queue handling.
* </ul>
*/
class RilSapSocket : public RilSocket {
/**
* Function pointer to the ril initialization funtion.
*
* @param Ril environment variable with place request and
* response handlers and timeout handler.
*
* @param Number of arguements for the initialization function.
*
* @param Arguements to the initialization function used to
* generate instance id of the ril daemon.
*
* @return Radio functions with handlers for onRequest, onStateRequest,
* supports, onCancel and getVersion.
*/
RIL_RadioFunctions *(*UimInit)(const struct RIL_Env *, int argc, char **argv);
/**
* Place holder for the radio functions returned by the initialization
* function. Currenty only onRequest handler is being used.
*/
RIL_RadioFunctions* uimFuncs;
/**
* Wrapper struct for handling the requests in the queue.
*/
typedef struct SapSocketRequest {
int token;
MsgHeader* curr;
struct SapSocketRequest* p_next;
RIL_SOCKET_ID socketId;
} SapSocketRequest;
/**
* Queue for requests that are pending dispatch.
*/
Ril_queue<SapSocketRequest> dispatchQueue;
/**
* Queue for requests that are dispatched but are pending response
*/
Ril_queue<SapSocketRequest> pendingResponseQueue;
public:
/**
* Initialize the socket and add the socket to the list.
*
* @param Name of the socket.
* @param Radio functions to be used by the socket.
*/
static void initSapSocket(const char *socketName,
RIL_RadioFunctions *uimFuncs);
/**
* Process requests from the dispatch request queue.
* @param Request to be dispatched.
*/
int processRequest(MsgHeader *request);
/**
* Ril envoronment variable that holds the request and
* unsol response handlers.
*/
static struct RIL_Env uimRilEnv;
/**
* Function to print the socket list.
*/
static void printList();
/**
* Clean up method to be called on command close.
*/
void onCommandsSocketClosed(void);
/**
* Datatype to handle the socket list.
*/
typedef struct RilSapSocketList {
RilSapSocket* socket;
RilSapSocketList *next;
} RilSapSocketList;
protected:
/**
* Process each record read from the socket and
* push a new request created from that record to
* the dispatch request queue.
*
* @param The record data.
* @param The record length.
*/
void pushRecord(void *record, size_t recordlen);
/**
* Socket handler to be called when a request has
* been completed.
*
* @param Token associated with the request.
* @param Error, if any, while processing the request.
* @param The response payload.
* @param Response payload length.
*/
void onRequestComplete(RIL_Token t,RIL_Errno e,
void *response, size_t response_len);
/**
* Socket handler to be called when there is an
* unsolicited response.
*
* @param Message id.
* @param Response data.
* @param Response data length.
*/
void onUnsolicitedResponse(int unsolResponse,
void *data, size_t datalen);
/**
* Class method to get the socket from the socket list.
*
* @param Socket id.
* @return the sap socket.
*/
static RilSapSocket* getSocketById(RIL_SOCKET_ID socketId);
/**
* Method to send response to SAP. It does an atomic write operation on the
* socket.
*
* @param the response header with the payload.
*/
void sendResponse(MsgHeader *hdr);
/**
* A loop for processing the requests in the request dispatch queue.
*/
void *processRequestsLoop(void);
/**
* Class method to add the sap socket to the list of sockets.
* Does nothing if the socket is already present in the list.
* Otherwise, calls the constructor of the parent class(To startlistening)
* and add socket to the socket list.
*/
static void addSocketToList(const char *socketName, RIL_SOCKET_ID socketid,
RIL_RadioFunctions *uimFuncs);
/**
* Check if a socket of the given name exists in the socket list.
*
* @param Socket name.
* @return true if exists, false otherwise.
*/
static bool SocketExists(const char *socketName);
/**
* Send a clean up SAP DISCONNECT if the socket disconnects before doing a SAP
* disconnect.
*/
void sendDisconnect(void);
/**
* Dispatch the clean up disconnect request.
*/
void dispatchDisconnect(MsgHeader *req);
private:
/**
* Constructor.
*
* @param Socket name.
* @param Socket id.
* @param Radio functions.
*/
RilSapSocket(const char *socketName,
RIL_SOCKET_ID socketId,
RIL_RadioFunctions *inputUimFuncs);
/**
* Called by the processRequest method to dispatch the request to
* the lower layers. It calls the on request function.
*
* @param The request message.
*/
void dispatchRequest(MsgHeader *request);
/**
* Class method that selects the socket on which the onRequestComplete
* is called.
*
* @param Token associated with the request.
* @param Error, if any, while processing the request.
* @param The response payload.
* @param Response payload length.
*/
static void sOnRequestComplete(RIL_Token t,
RIL_Errno e, void *response, size_t responselen);
#if defined(ANDROID_MULTI_SIM)
/**
* Class method that selects the socket on which the onUnsolicitedResponse
* is called.
*
* @param Message id.
* @param Response data.
* @param Response data length.
* @param Socket id.
*/
static void sOnUnsolicitedResponse(int unsolResponse, const void *data,
size_t datalen, RIL_SOCKET_ID socket_id);
#else
/**
* Class method that selects the socket on which the onUnsolicitedResponse
* is called.
*
* @param Message id.
* @param Response data.
* @param Response data length.
*/
static void sOnUnsolicitedResponse(int unsolResponse, const void *data,
size_t datalen);
#endif
};
#endif /*RIL_UIM_SOCKET_H_INCLUDED*/

@ -0,0 +1,177 @@
/*
* Copyright (C) 2014 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.
*/
extern "C"
void *ril_socket_process_requests_loop(void *arg);
#include "RilSocket.h"
#include <cutils/sockets.h>
#include <utils/Log.h>
#include <assert.h>
#define SOCKET_LISTEN_BACKLOG 0
int RilSocket::socketInit(void) {
int ret;
listenCb = &RilSocket::sSocketListener;
commandCb = &RilSocket::sSocketRequestsHandler;
listenFd = android_get_control_socket(name);
//Start listening
ret = listen(listenFd, SOCKET_LISTEN_BACKLOG);
if (ret < 0) {
RLOGE("Failed to listen on %s socket '%d': %s",
name, listenFd, strerror(errno));
return ret;
}
//Add listen event to the event loop
ril_event_set(&listenEvent, listenFd, false, listenCb, this);
rilEventAddWakeup_helper(&listenEvent);
return ret;
}
void RilSocket::sSocketListener(int fd, short flags, void *param) {
RilSocket *theSocket = (RilSocket *) param;
MySocketListenParam listenParam;
listenParam.socket = theSocket;
listenParam.sListenParam.type = RIL_SAP_SOCKET;
listenCallback_helper(fd, flags, (void*)&listenParam);
}
void RilSocket::onNewCommandConnect() {
pthread_attr_t attr;
PthreadPtr pptr = ril_socket_process_requests_loop;
int result;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//Start socket request processing loop thread
result = pthread_create(&socketThreadId, &attr, pptr, this);
if(result < 0) {
RLOGE("pthread_create failed with result:%d",result);
}
RLOGE("New socket command connected and socket request thread started");
}
void RilSocket::sSocketRequestsHandler(int fd, short flags, void *param) {
socketClient *sc = (socketClient *) param;
RilSocket *theSocket = sc->socketPtr;
RecordStream *rs = sc->rs;
theSocket->socketRequestsHandler(fd, flags, rs);
}
void RilSocket::socketRequestsHandler(int fd, short flags, RecordStream *p_rs) {
int ret;
assert(fd == commandFd);
void *p_record;
size_t recordlen;
for (;;) {
/* loop until EAGAIN/EINTR, end of stream, or other error */
ret = record_stream_get_next(p_rs, &p_record, &recordlen);
if (ret == 0 && p_record == NULL) {
/* end-of-stream */
break;
} else if (ret < 0) {
break;
} else if (ret == 0) {
pushRecord(p_record, recordlen);
}
}
if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {
/* fatal error or end-of-stream */
if (ret != 0) {
RLOGE("error on reading command socket errno:%d\n", errno);
} else {
RLOGW("EOS. Closing command socket.");
}
close(commandFd);
commandFd = -1;
ril_event_del(&callbackEvent);
record_stream_free(p_rs);
/* start listening for new connections again */
rilEventAddWakeup_helper(&listenEvent);
onCommandsSocketClosed();
}
}
void RilSocket::setListenFd(int fd) {
listenFd = fd;
}
void RilSocket::setCommandFd(int fd) {
commandFd = fd;
}
int RilSocket::getListenFd(void) {
return listenFd;
}
int RilSocket::getCommandFd(void) {
return commandFd;
}
void RilSocket::setListenCb(ril_event_cb cb) {
listenCb = cb;
}
void RilSocket::setCommandCb(ril_event_cb cb) {
commandCb = cb;
}
ril_event_cb RilSocket::getListenCb(void) {
return listenCb;
}
ril_event_cb RilSocket::getCommandCb(void) {
return commandCb;
}
void RilSocket::setListenEvent(ril_event event) {
listenEvent = event;
}
void RilSocket::setCallbackEvent(ril_event event) {
callbackEvent = event;
}
ril_event* RilSocket::getListenEvent(void) {
return &listenEvent;
}
ril_event* RilSocket::getCallbackEvent(void) {
return &callbackEvent;
}
extern "C"
void *ril_socket_process_requests_loop(void *arg) {
RilSocket *socket = (RilSocket *)arg;
socket->processRequestsLoop();
return NULL;
}

@ -0,0 +1,270 @@
/*
* Copyright (C) 2014 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.
*/
#ifndef RIL_SOCKET_H_INCLUDED
#define RIL_SOCKET_H_INCLUDED
#include "ril_ex.h"
#include "rilSocketQueue.h"
#include <ril_event.h>
using namespace std;
/**
* Abstract socket class representing sockets in rild.
* <p>
* This class performs the following functions :
* <ul>
* <li> Start socket listen.
* <li> Handle socket listen and command callbacks.
* </ul>
*/
class RilSocket {
protected:
/**
* Socket name.
*/
const char* name;
/**
* Socket id.
*/
RIL_SOCKET_ID id;
/**
* Listen socket file descriptor.
*/
int listenFd = -1;
/**
* Commands socket file descriptor.
*/
int commandFd = -1;
/**
* Socket request loop thread id.
*/
pthread_t socketThreadId;
/**
* Listen event callack. Callback called when the other ends does accept.
*/
ril_event_cb listenCb;
/**
* Commands event callack.Callback called when there are requests from the other side.
*/
ril_event_cb commandCb;
/**
* Listen event to be added to eventloop after socket listen.
*/
struct ril_event listenEvent;
/**
* Commands event to be added to eventloop after accept.
*/
struct ril_event callbackEvent;
/**
* Static socket listen handler. Chooses the socket to call the listen callback
* from ril.cpp.
*
* @param Listen fd.
* @param flags.
* @param Parameter for the listen handler.
*/
static void sSocketListener(int fd, short flags, void *param);
/**
* Static socket request handler. Chooses the socket to call the request handler on.
*
* @param Commands fd.
* @param flags.
* @param Parameter for the request handler.
*/
static void sSocketRequestsHandler(int fd, short flags, void *param);
/**
* Process record from the record stream and push the requests onto the queue.
*
* @param record data.
* @param record length.
*/
virtual void pushRecord(void *record, size_t recordlen) = 0;
/**
* Socket lock for writing data on the socket.
*/
pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
/**
* The loop to process the incoming requests.
*/
virtual void *processRequestsLoop(void) = 0;
private:
friend void *::ril_socket_process_requests_loop(void *arg);
public:
/**
* Constructor.
*
* @param Socket name.
* @param Socket id.
*/
RilSocket(const char* socketName, RIL_SOCKET_ID socketId) {
name = socketName;
id = socketId;
}
/**
* Clean up function on commands socket close.
*/
virtual void onCommandsSocketClosed(void) = 0;
/**
* Function called on new commands socket connect. Request loop thread is started here.
*/
void onNewCommandConnect(void);
/**
* Set listen socket fd.
*
* @param Input fd.
*/
void setListenFd(int listenFd);
/**
* Set commands socket fd.
*
* @param Input fd.
*/
void setCommandFd(int commandFd);
/**
* Get listen socket fd.
*
* @return Listen fd.
*/
int getListenFd(void);
/**
* Get commands socket fd.
*
* @return Commands fd.
*/
int getCommandFd(void);
/**
* Set listen event callback.
*
* @param Input event callback.
*/
void setListenCb(ril_event_cb listenCb);
/**
* Set command event callback.
*
* @param Input event callback.
*/
void setCommandCb(ril_event_cb commandCb);
/**
* Get listen event callback.
*
* @return Listen event callback.
*/
ril_event_cb getListenCb(void);
/**
* Gey command event callback.
*
* @return Command event callback.
*/
ril_event_cb getCommandCb(void);
/**
* Set listen event.
*
* @param Input event.
*/
void setListenEvent(ril_event listenEvent);
/**
* Set command callback event.
*
* @param Input event.
*/
void setCallbackEvent(ril_event commandEvent);
/**
* Get listen event.
*
* @return Listen event.
*/
ril_event* getListenEvent(void);
/**
* Get commands callback event.
*
* @return Commands callback event.
*/
ril_event* getCallbackEvent(void);
virtual ~RilSocket(){}
protected:
/**
* Start listening on the socket and add the socket listen callback event.
*
* @return Result of the socket listen.
*/
int socketInit(void);
/**
* Socket request handler
*
* @param Commands fd.
* @param flags.
* @param Record stream.
*/
void socketRequestsHandler(int fd, short flags, RecordStream *rs);
};
class socketClient {
public:
RilSocket *socketPtr;
RecordStream *rs;
socketClient(RilSocket *socketPtr, RecordStream *rs) {
this->socketPtr = socketPtr;
this->rs = rs;
}
};
typedef struct MySocketListenParam {
SocketListenParam sListenParam;
RilSocket *socket;
} MySocketListenParam;
typedef void* (RilSocket::*RilSocketFuncPtr)(void);
typedef void (RilSocket::*RilSocketEventPtr)(int fd,short flags, void *param);
typedef void* (*PthreadPtr)(void*);
#endif

@ -18,7 +18,6 @@
#define LOG_TAG "RILC" #define LOG_TAG "RILC"
#include <hardware_legacy/power.h> #include <hardware_legacy/power.h>
#include <telephony/ril.h> #include <telephony/ril.h>
#include <telephony/ril_cdma_sms.h> #include <telephony/ril_cdma_sms.h>
#include <cutils/sockets.h> #include <cutils/sockets.h>
@ -29,11 +28,9 @@
#include <pthread.h> #include <pthread.h>
#include <binder/Parcel.h> #include <binder/Parcel.h>
#include <cutils/jstring.h> #include <cutils/jstring.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/limits.h> #include <sys/limits.h>
#include <pwd.h> #include <pwd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
@ -49,12 +46,14 @@
#include <assert.h> #include <assert.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <cutils/properties.h> #include <cutils/properties.h>
#include <RilSapSocket.h>
#include <ril_event.h> extern "C" void
RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen);
namespace android { namespace android {
#define PHONE_PROCESS "radio" #define PHONE_PROCESS "radio"
#define BLUETOOTH_PROCESS "bluetooth"
#define SOCKET_NAME_RIL "rild" #define SOCKET_NAME_RIL "rild"
#define SOCKET2_NAME_RIL "rild2" #define SOCKET2_NAME_RIL "rild2"
@ -148,17 +147,6 @@ typedef struct UserCallbackInfo {
struct UserCallbackInfo *p_next; struct UserCallbackInfo *p_next;
} UserCallbackInfo; } UserCallbackInfo;
typedef struct SocketListenParam {
RIL_SOCKET_ID socket_id;
int fdListen;
int fdCommand;
char* processName;
struct ril_event* commands_event;
struct ril_event* listen_event;
void (*processCommandsCallback)(int fd, short flags, void *param);
RecordStream *p_rs;
} SocketListenParam;
extern "C" const char * requestToString(int request); extern "C" const char * requestToString(int request);
extern "C" const char * failCauseToString(RIL_Errno); extern "C" const char * failCauseToString(RIL_Errno);
extern "C" const char * callStateToString(RIL_CallState); extern "C" const char * callStateToString(RIL_CallState);
@ -385,7 +373,7 @@ static char * RIL_getRilSocketName() {
} }
extern "C" extern "C"
void RIL_setRilSocketName(char * s) { void RIL_setRilSocketName(const char * s) {
strncpy(rild, s, MAX_SOCKET_NAME_LENGTH); strncpy(rild, s, MAX_SOCKET_NAME_LENGTH);
} }
@ -2127,7 +2115,7 @@ blockingWrite(int fd, const void *buffer, size_t len) {
return -1; return -1;
} }
} }
RLOGE("RIL Response bytes written:%d", writeOffset);
return 0; return 0;
} }
@ -3898,9 +3886,19 @@ static void listenCallback (int fd, short flags, void *param) {
int err; int err;
int is_phone_socket; int is_phone_socket;
int fdCommand = -1; int fdCommand = -1;
char* processName;
RecordStream *p_rs; RecordStream *p_rs;
MySocketListenParam* listenParam;
RilSocket *sapSocket = NULL;
socketClient *sClient = NULL;
SocketListenParam *p_info = (SocketListenParam *)param; SocketListenParam *p_info = (SocketListenParam *)param;
if(RIL_SAP_SOCKET == p_info->type) {
listenParam = (MySocketListenParam *)param;
sapSocket = listenParam->socket;
}
struct sockaddr_un peeraddr; struct sockaddr_un peeraddr;
socklen_t socklen = sizeof (peeraddr); socklen_t socklen = sizeof (peeraddr);
@ -3909,15 +3907,27 @@ static void listenCallback (int fd, short flags, void *param) {
struct passwd *pwd = NULL; struct passwd *pwd = NULL;
assert (*p_info->fdCommand < 0); if(NULL == sapSocket) {
assert (fd == *p_info->fdListen); assert (*p_info->fdCommand < 0);
assert (fd == *p_info->fdListen);
processName = PHONE_PROCESS;
} else {
assert (sapSocket->commandFd < 0);
assert (fd == sapSocket->listenFd);
processName = BLUETOOTH_PROCESS;
}
fdCommand = accept(fd, (sockaddr *) &peeraddr, &socklen); fdCommand = accept(fd, (sockaddr *) &peeraddr, &socklen);
if (fdCommand < 0 ) { if (fdCommand < 0 ) {
RLOGE("Error on accept() errno:%d", errno); RLOGE("Error on accept() errno:%d", errno);
/* start listening for new connections again */ /* start listening for new connections again */
rilEventAddWakeup(p_info->listen_event); if(NULL == sapSocket) {
rilEventAddWakeup(p_info->listen_event);
} else {
rilEventAddWakeup(sapSocket->getListenEvent());
}
return; return;
} }
@ -3933,7 +3943,7 @@ static void listenCallback (int fd, short flags, void *param) {
errno = 0; errno = 0;
pwd = getpwuid(creds.uid); pwd = getpwuid(creds.uid);
if (pwd != NULL) { if (pwd != NULL) {
if (strcmp(pwd->pw_name, p_info->processName) == 0) { if (strcmp(pwd->pw_name, processName) == 0) {
is_phone_socket = 1; is_phone_socket = 1;
} else { } else {
RLOGE("RILD can't accept socket from process %s", pwd->pw_name); RLOGE("RILD can't accept socket from process %s", pwd->pw_name);
@ -3946,17 +3956,24 @@ static void listenCallback (int fd, short flags, void *param) {
} }
if (!is_phone_socket) { if (!is_phone_socket) {
RLOGE("RILD must accept socket from %s", p_info->processName); RLOGE("RILD must accept socket from %s", processName);
close(fdCommand); close(fdCommand);
fdCommand = -1; fdCommand = -1;
onCommandsSocketClosed(p_info->socket_id); if(NULL == sapSocket) {
onCommandsSocketClosed(p_info->socket_id);
/* start listening for new connections again */ /* start listening for new connections again */
rilEventAddWakeup(p_info->listen_event); rilEventAddWakeup(p_info->listen_event);
} else {
sapSocket->onCommandsSocketClosed();
return; /* start listening for new connections again */
rilEventAddWakeup(sapSocket->getListenEvent());
}
return;
} }
ret = fcntl(fdCommand, F_SETFL, O_NONBLOCK); ret = fcntl(fdCommand, F_SETFL, O_NONBLOCK);
@ -3965,20 +3982,30 @@ static void listenCallback (int fd, short flags, void *param) {
RLOGE ("Error setting O_NONBLOCK errno:%d", errno); RLOGE ("Error setting O_NONBLOCK errno:%d", errno);
} }
RLOGI("libril: new connection to %s", rilSocketIdToString(p_info->socket_id)); if(NULL == sapSocket) {
RLOGI("libril: new connection to %s", rilSocketIdToString(p_info->socket_id));
p_info->fdCommand = fdCommand; p_info->fdCommand = fdCommand;
p_rs = record_stream_new(p_info->fdCommand, MAX_COMMAND_BYTES);
p_info->p_rs = p_rs;
p_rs = record_stream_new(p_info->fdCommand, MAX_COMMAND_BYTES); ril_event_set (p_info->commands_event, p_info->fdCommand, 1,
p_info->p_rs = p_rs;
ril_event_set (p_info->commands_event, p_info->fdCommand, 1,
p_info->processCommandsCallback, p_info); p_info->processCommandsCallback, p_info);
rilEventAddWakeup (p_info->commands_event);
rilEventAddWakeup (p_info->commands_event); onNewCommandConnect(p_info->socket_id);
} else {
RLOGI("libril: new connection");
onNewCommandConnect(p_info->socket_id); sapSocket->setCommandFd(fdCommand);
p_rs = record_stream_new(sapSocket->getCommandFd(), MAX_COMMAND_BYTES);
sClient = new socketClient(sapSocket,p_rs);
ril_event_set (sapSocket->getCallbackEvent(), sapSocket->getCommandFd(), 1,
sapSocket->getCommandCb(), sClient);
rilEventAddWakeup(sapSocket->getCallbackEvent());
sapSocket->onNewCommandConnect();
}
} }
static void freeDebugCallbackArgs(int number, char **args) { static void freeDebugCallbackArgs(int number, char **args) {
@ -4464,6 +4491,33 @@ RIL_register (const RIL_RadioFunctions *callbacks) {
} }
extern "C" void
RIL_register_socket (RIL_RadioFunctions *(*Init)(const struct RIL_Env *, int, char **),RIL_SOCKET_TYPE socketType, int argc, char **argv) {
RIL_RadioFunctions* UimFuncs = NULL;
if(Init) {
UimFuncs = Init(&RilSapSocket::uimRilEnv, argc, argv);
switch(socketType) {
case RIL_SAP_SOCKET:
RilSapSocket::initSapSocket("sap_uim_socket1", UimFuncs);
#if (SIM_COUNT >= 2)
RilSapSocket::initSapSocket("sap_uim_socket2", UimFuncs);
#endif
#if (SIM_COUNT >= 3)
RilSapSocket::initSapSocket("sap_uim_socket3", UimFuncs);
#endif
#if (SIM_COUNT >= 4)
RilSapSocket::initSapSocket("sap_uim_socket4", UimFuncs);
#endif
}
}
}
static int static int
checkAndDequeueRequestInfo(struct RequestInfo *pRI) { checkAndDequeueRequestInfo(struct RequestInfo *pRI) {
int ret = 0; int ret = 0;
@ -5185,3 +5239,15 @@ rilSocketIdToString(RIL_SOCKET_ID socket_id)
} }
} /* namespace android */ } /* namespace android */
void rilEventAddWakeup_helper(struct ril_event *ev) {
android::rilEventAddWakeup(ev);
}
void listenCallback_helper(int fd, short flags, void *param) {
android::listenCallback(fd, flags, param);
}
int blockingWrite_helper(int fd, void *buffer, size_t len) {
return android::blockingWrite(fd, buffer, len);
}

@ -0,0 +1,167 @@
/*
* Copyright (C) 2014 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 "pb_decode.h"
#include <pthread.h>
#include <hardware/ril/librilutils/proto/sap-api.pb.h>
#include <utils/Log.h>
using namespace std;
/**
* Template queue class to handling requests for a rild socket.
* <p>
* This class performs the following functions :
* <ul>
* <li>Enqueue.
* <li>Dequeue.
* <li>Check and dequeue.
* </ul>
*/
template <typename T>
class Ril_queue {
/**
* Mutex attribute used in queue mutex initialization.
*/
pthread_mutexattr_t attr;
/**
* Queue mutex variable for synchronized queue access.
*/
pthread_mutex_t mutex_instance;
/**
* Condition to be waited on for dequeuing.
*/
pthread_cond_t cond;
/**
* Front of the queue.
*/
T *front;
public:
/**
* Remove the first element of the queue.
*
* @return first element of the queue.
*/
T* dequeue(void);
/**
* Add a request to the front of the queue.
*
* @param Request to be added.
*/
void enqueue(T* request);
/**
* Check if the queue is empty.
*/
int empty(void);
/**
* Check and remove an element with a particular message id and token.
*
* @param Request message id.
* @param Request token.
*/
int checkAndDequeue( MsgId id, int token);
/**
* Queue constructor.
*/
Ril_queue(void);
};
template <typename T>
Ril_queue<T>::Ril_queue(void) {
pthread_mutexattr_init(&attr);
pthread_mutex_init(&mutex_instance, &attr);
cond = PTHREAD_COND_INITIALIZER;
front = NULL;
}
template <typename T>
T* Ril_queue<T>::dequeue(void) {
T* temp = NULL;
pthread_mutex_lock(&mutex_instance);
while(empty()) {
pthread_cond_wait(&cond, &mutex_instance);
}
temp = this->front;
if(NULL != this->front->p_next) {
this->front = this->front->p_next;
} else {
this->front = NULL;
}
pthread_mutex_unlock(&mutex_instance);
return temp;
}
template <typename T>
void Ril_queue<T>::enqueue(T* request) {
pthread_mutex_lock(&mutex_instance);
if(NULL == this->front) {
this->front = request;
request->p_next = NULL;
} else {
request->p_next = this->front;
this->front = request;
}
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex_instance);
}
template <typename T>
int Ril_queue<T>::checkAndDequeue(MsgId id, int token) {
int ret = 0;
T* temp;
pthread_mutex_lock(&mutex_instance);
for(T **ppCur = &(this->front); *ppCur != NULL; ppCur = &((*ppCur)->p_next)) {
if (token == (*ppCur)->token && id == (*ppCur)->curr->id) {
ret = 1;
temp = *ppCur;
*ppCur = (*ppCur)->p_next;
free(temp);
break;
}
}
pthread_mutex_unlock(&mutex_instance);
return ret;
}
template <typename T>
int Ril_queue<T>::empty(void) {
if(this->front == NULL) {
return 1;
} else {
return 0;
}
}

@ -0,0 +1,48 @@
/*
* Copyright (C) 2014 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.
*/
#ifndef RIL_EX_H_INCLUDED
#define RIL_EX_H_INCLUDED
#include <telephony/ril.h>
#include <telephony/record_stream.h>
#define NUM_ELEMS_SOCKET(a) (sizeof (a) / sizeof (a)[0])
void rilEventAddWakeup_helper(struct ril_event *ev);
void listenCallback_helper(int fd, short flags, void *param);
int blockingWrite_helper(int fd, void* data, size_t len);
enum SocketWakeType {DONT_WAKE, WAKE_PARTIAL};
typedef enum {
RIL_TELEPHONY_SOCKET,
RIL_SAP_SOCKET
} RIL_SOCKET_TYPE;
typedef struct SocketListenParam {
RIL_SOCKET_ID socket_id;
int fdListen;
int fdCommand;
char* processName;
struct ril_event* commands_event;
struct ril_event* listen_event;
void (*processCommandsCallback)(int fd, short flags, void *param);
RecordStream *p_rs;
RIL_SOCKET_TYPE type;
} SocketListenParam;
#endif
Loading…
Cancel
Save