Introduction of the new SAP-UIM socket
authorDheeraj Shetty <dshetty@codeaurora.org>
Wed, 2 Jul 2014 19:27:57 +0000 (21:27 +0200)
committerEthan Chen <intervigil@gmail.com>
Mon, 19 Oct 2015 19:16:41 +0000 (12:16 -0700)
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

ril/libril/Android.mk
ril/libril/RilSapSocket.cpp [new file with mode: 0644]
ril/libril/RilSapSocket.h [new file with mode: 0644]
ril/libril/RilSocket.cpp [new file with mode: 0644]
ril/libril/RilSocket.h [new file with mode: 0644]
ril/libril/ril.cpp
ril/libril/rilSocketQueue.h [new file with mode: 0644]
ril/libril/ril_ex.h [new file with mode: 0644]

index 71278b03890f816f4aab96204369977c5b91a4e5..a310d73b80d24072402aaa86638eeaabf25823cd 100644 (file)
@@ -7,7 +7,9 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
     ril.cpp \
-    ril_event.cpp
+    ril_event.cpp\
+    RilSocket.cpp \
+    RilSapSocket.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
     liblog \
@@ -15,7 +17,10 @@ LOCAL_SHARED_LIBRARIES := \
     libbinder \
     libcutils \
     libhardware_legacy \
-    librilutils
+    librilutils \
+
+LOCAL_STATIC_LIBRARIES := \
+    libnanopb-c-2.8.0-enable_malloc \
 
 ifneq ($(filter xmm6262 xmm6360,$(BOARD_MODEM_TYPE)),)
 LOCAL_CFLAGS := -DMODEM_TYPE_XMM6262
@@ -30,10 +35,15 @@ ifeq ($(BOARD_MODEM_TYPE),m7450)
 LOCAL_CFLAGS := -DMODEM_TYPE_M7450
 endif
 
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADER)/librilutils
+LOCAL_C_INCLUDES += external/nanopb-c
+
 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
 # =========================================
diff --git a/ril/libril/RilSapSocket.cpp b/ril/libril/RilSapSocket.cpp
new file mode 100644 (file)
index 0000000..92cc98c
--- /dev/null
@@ -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");
+}
diff --git a/ril/libril/RilSapSocket.h b/ril/libril/RilSapSocket.h
new file mode 100644 (file)
index 0000000..4261f93
--- /dev/null
@@ -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*/
diff --git a/ril/libril/RilSocket.cpp b/ril/libril/RilSocket.cpp
new file mode 100644 (file)
index 0000000..a002d94
--- /dev/null
@@ -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;
+}
diff --git a/ril/libril/RilSocket.h b/ril/libril/RilSocket.h
new file mode 100644 (file)
index 0000000..053df3e
--- /dev/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
index 975518d18c5de86aad4c6cb1680337568f03567b..fe1c65f245a415a875493df8c6d89ea975357170 100644 (file)
@@ -18,7 +18,6 @@
 #define LOG_TAG "RILC"
 
 #include <hardware_legacy/power.h>
-
 #include <telephony/ril.h>
 #include <telephony/ril_cdma_sms.h>
 #include <cutils/sockets.h>
 #include <pthread.h>
 #include <binder/Parcel.h>
 #include <cutils/jstring.h>
-
 #include <sys/types.h>
 #include <sys/limits.h>
 #include <pwd.h>
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <assert.h>
 #include <netinet/in.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 {
 
 #define PHONE_PROCESS "radio"
+#define BLUETOOTH_PROCESS "bluetooth"
 
 #define SOCKET_NAME_RIL "rild"
 #define SOCKET2_NAME_RIL "rild2"
@@ -148,17 +147,6 @@ typedef struct UserCallbackInfo {
     struct UserCallbackInfo *p_next;
 } 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 * failCauseToString(RIL_Errno);
 extern "C" const char * callStateToString(RIL_CallState);
@@ -385,7 +373,7 @@ static char * RIL_getRilSocketName() {
 }
 
 extern "C"
-void RIL_setRilSocketName(char * s) {
+void RIL_setRilSocketName(const char * s) {
     strncpy(rild, s, MAX_SOCKET_NAME_LENGTH);
 }
 
@@ -2127,7 +2115,7 @@ blockingWrite(int fd, const void *buffer, size_t len) {
             return -1;
         }
     }
-
+    RLOGE("RIL Response bytes written:%d", writeOffset);
     return 0;
 }
 
@@ -3898,9 +3886,19 @@ static void listenCallback (int fd, short flags, void *param) {
     int err;
     int is_phone_socket;
     int fdCommand = -1;
+    char* processName;
     RecordStream *p_rs;
+    MySocketListenParam* listenParam;
+    RilSocket *sapSocket = NULL;
+    socketClient *sClient = NULL;
+
     SocketListenParam *p_info = (SocketListenParam *)param;
 
+    if(RIL_SAP_SOCKET == p_info->type) {
+        listenParam = (MySocketListenParam *)param;
+        sapSocket = listenParam->socket;
+    }
+
     struct sockaddr_un peeraddr;
     socklen_t socklen = sizeof (peeraddr);
 
@@ -3909,15 +3907,27 @@ static void listenCallback (int fd, short flags, void *param) {
 
     struct passwd *pwd = NULL;
 
-    assert (*p_info->fdCommand < 0);
-    assert (fd == *p_info->fdListen);
+    if(NULL == sapSocket) {
+        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);
 
     if (fdCommand < 0 ) {
         RLOGE("Error on accept() errno:%d", errno);
         /* start listening for new connections again */
-        rilEventAddWakeup(p_info->listen_event);
+        if(NULL == sapSocket) {
+            rilEventAddWakeup(p_info->listen_event);
+        } else {
+            rilEventAddWakeup(sapSocket->getListenEvent());
+        }
         return;
     }
 
@@ -3933,7 +3943,7 @@ static void listenCallback (int fd, short flags, void *param) {
         errno = 0;
         pwd = getpwuid(creds.uid);
         if (pwd != NULL) {
-            if (strcmp(pwd->pw_name, p_info->processName) == 0) {
+            if (strcmp(pwd->pw_name, processName) == 0) {
                 is_phone_socket = 1;
             } else {
                 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) {
-      RLOGE("RILD must accept socket from %s", p_info->processName);
+        RLOGE("RILD must accept socket from %s", processName);
 
-      close(fdCommand);
-      fdCommand = -1;
+        close(fdCommand);
+        fdCommand = -1;
 
-      onCommandsSocketClosed(p_info->socket_id);
+        if(NULL == sapSocket) {
+            onCommandsSocketClosed(p_info->socket_id);
 
-      /* start listening for new connections again */
-      rilEventAddWakeup(p_info->listen_event);
+            /* start listening for new connections again */
+            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);
@@ -3965,20 +3982,30 @@ static void listenCallback (int fd, short flags, void *param) {
         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);
-
-    p_info->p_rs = p_rs;
-
-    ril_event_set (p_info->commands_event, p_info->fdCommand, 1,
+        ril_event_set (p_info->commands_event, p_info->fdCommand, 1,
         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) {
@@ -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
 checkAndDequeueRequestInfo(struct RequestInfo *pRI) {
     int ret = 0;
@@ -5185,3 +5239,15 @@ rilSocketIdToString(RIL_SOCKET_ID socket_id)
 }
 
 } /* 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);
+}
diff --git a/ril/libril/rilSocketQueue.h b/ril/libril/rilSocketQueue.h
new file mode 100644 (file)
index 0000000..eaa5155
--- /dev/null
@@ -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;
+    }
+}
diff --git a/ril/libril/ril_ex.h b/ril/libril/ril_ex.h
new file mode 100644 (file)
index 0000000..8e15d65
--- /dev/null
@@ -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