OSDN Git Service

DO NOT MERGE Fix security vulnerability in pre-O rild code. am: c4c7c551b1 -s ours...
authorSanket Padawe <sanketpadawe@google.com>
Thu, 10 Aug 2017 03:43:57 +0000 (03:43 +0000)
committerandroid-build-merger <android-build-merger@google.com>
Thu, 10 Aug 2017 03:43:57 +0000 (03:43 +0000)
am: e90cce1ae7  -s ours

Change-Id: Ibb3ea8590c4537fbae682956040e4a590e3616b8

17 files changed:
include/telephony/ril.h
libril/Android.mk
libril/RilSapSocket.cpp [new file with mode: 0644]
libril/RilSapSocket.h [new file with mode: 0644]
libril/RilSocket.cpp [new file with mode: 0644]
libril/RilSocket.h [new file with mode: 0644]
libril/ril.cpp
libril/rilSocketQueue.h [new file with mode: 0644]
libril/ril_commands.h
libril/ril_event.cpp
libril/ril_ex.h [new file with mode: 0644]
libril/ril_unsol_commands.h
librilutils/Android.mk
librilutils/proto/sap-api.options [new file with mode: 0644]
librilutils/proto/sap-api.proto [new file with mode: 0644]
rild/Android.mk
rild/rild.c

index 62521f4..2e71367 100644 (file)
@@ -113,7 +113,8 @@ typedef enum {
     RIL_E_SS_MODIFIED_TO_DIAL = 24,             /* SS request modified to DIAL */
     RIL_E_SS_MODIFIED_TO_USSD = 25,             /* SS request modified to USSD */
     RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,      /* Subscription not supported by RIL */
-    RIL_E_SS_MODIFIED_TO_SS = 27                /* SS request modified to different SS request */
+    RIL_E_SS_MODIFIED_TO_SS = 27,               /* SS request modified to different SS request */
+    RIL_E_LCE_NOT_SUPPORTED = 36                /* LCE service not supported(36 in RILConstants.java) */
 
 
 } RIL_Errno;
@@ -162,7 +163,8 @@ typedef enum {
     RADIO_TECH_LTE = 14,
     RADIO_TECH_HSPAP = 15, // HSPA+
     RADIO_TECH_GSM = 16, // Only supports voice
-    RADIO_TECH_TD_SCDMA = 17
+    RADIO_TECH_TD_SCDMA = 17,
+    RADIO_TECH_IWLAN = 18
 } RIL_RadioTechnology;
 
 typedef enum {
@@ -565,6 +567,27 @@ typedef struct {
                         */
 } RIL_NeighboringCell;
 
+typedef struct {
+  char lce_status;                 /* LCE service status:
+                                    * -1 = not supported;
+                                    * 0 = stopped;
+                                    * 1 = active.
+                                    */
+  unsigned int actual_interval_ms; /* actual LCE reporting interval,
+                                    * meaningful only if LCEStatus = 1.
+                                    */
+} RIL_LceStatusInfo;
+
+typedef struct {
+  unsigned int last_hop_capacity_kbps; /* last-hop cellular capacity: kilobits/second. */
+  unsigned char confidence_level;      /* capacity estimate confidence: 0-100 */
+  unsigned char lce_suspended;         /* LCE report going to be suspended? (e.g., radio
+                                        * moves to inactive state or network type change)
+                                        * 1 = suspended;
+                                        * 0 = not suspended.
+                                        */
+} RIL_LceDataInfo;
+
 /* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
 typedef enum {
     CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
@@ -593,6 +616,11 @@ typedef enum {
     CALL_FAIL_ERROR_UNSPECIFIED = 0xffff
 } RIL_LastCallFailCause;
 
+typedef struct {
+  RIL_LastCallFailCause cause_code;
+  char *                vendor_cause;
+} RIL_LastCallFailCauseInfo;
+
 /* See RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE */
 typedef enum {
     PDP_FAIL_NONE = 0, /* No error, connection ok */
@@ -1388,6 +1416,24 @@ typedef struct {
     int enabled;
 } RIL_DataProfileInfo;
 
+/* Tx Power Levels */
+#define RIL_NUM_TX_POWER_LEVELS     5
+
+typedef struct {
+
+  /* period (in ms) when modem is power collapsed */
+  uint32_t sleep_mode_time_ms;
+
+  /* period (in ms) when modem is awake and in idle mode*/
+  uint32_t idle_mode_time_ms;
+
+  /* period (in ms) for which Tx is active */
+  uint32_t tx_mode_time_ms[RIL_NUM_TX_POWER_LEVELS];
+
+  /* period (in ms) for which Rx is active */
+  uint32_t rx_mode_time_ms;
+} RIL_ActivityStatsInfo;
+
 /**
  * RIL_REQUEST_GET_SIM_STATUS
  *
@@ -4247,6 +4293,7 @@ typedef struct {
 /**
  * RIL_REQUEST_GET_DC_RT_INFO
  *
+ * The request is DEPRECATED, use RIL_REQUEST_GET_ACTIVITY_INFO
  * Requests the Data Connection Real Time Info
  *
  * "data" is NULL
@@ -4265,6 +4312,7 @@ typedef struct {
 /**
  * RIL_REQUEST_SET_DC_RT_INFO_RATE
  *
+ * The request is DEPRECATED
  * This is the minimum number of milliseconds between successive
  * RIL_UNSOL_DC_RT_INFO_CHANGED messages and defines the highest rate
  * at which RIL_UNSOL_DC_RT_INFO_CHANGED's will be sent. A value of
@@ -4317,9 +4365,7 @@ typedef struct {
  *
  * Used to get phone radio capablility.
  *
- * "data" is int *
- * ((int *)data)[0] is the phone radio access family defined in
- * RadioAccessFamily. It's a bit mask value to represent the support type.
+ * "data" is the RIL_RadioCapability structure
  *
  * Valid errors:
  *  SUCCESS
@@ -4347,6 +4393,72 @@ typedef struct {
  */
 #define RIL_REQUEST_SET_RADIO_CAPABILITY 131
 
+/**
+ * RIL_REQUEST_START_LCE
+ *
+ * Start Link Capacity Estimate (LCE) service if supported by the radio.
+ *
+ * "data" is const int *
+ * ((const int*)data)[0] specifies the desired reporting interval (ms).
+ * ((const int*)data)[1] specifies the LCE service mode. 1: PULL; 0: PUSH.
+ *
+ * "response" is the RIL_LceStatusInfo.
+ *
+ * Valid errors:
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE
+ * LCE_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_START_LCE 132
+
+/**
+ * RIL_REQUEST_STOP_LCE
+ *
+ * Stop Link Capacity Estimate (LCE) service, the STOP operation should be
+ * idempotent for the radio modem.
+ *
+ * "response" is the RIL_LceStatusInfo.
+ *
+ * Valid errors:
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE
+ * LCE_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_STOP_LCE 133
+
+/**
+ * RIL_REQUEST_PULL_LCEDATA
+ *
+ * Pull LCE service for capacity information.
+ *
+ * "response" is the RIL_LceDataInfo.
+ *
+ * Valid errors:
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE
+ * LCE_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_PULL_LCEDATA 134
+
+/**
+ * RIL_REQUEST_GET_ACTIVITY_INFO
+ *
+ * Get modem activity statisitics info.
+ *
+ * There can be multiple RIL_REQUEST_GET_ACTIVITY_INFO calls to modem.
+ * Once the response for the request is sent modem will clear
+ * current statistics information.
+ *
+ * "data" is null
+ * "response" is const RIL_ActivityStatsInfo *
+ *
+ * Valid errors:
+ *
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE (radio resetting)
+ * GENERIC_FAILURE
+ */
+#define RIL_REQUEST_GET_ACTIVITY_INFO 135
 
 /***********************************************************************/
 
@@ -4894,6 +5006,7 @@ typedef struct {
 /**
  * RIL_UNSOL_DC_RT_INFO_CHANGED
  *
+ * The message is DEPRECATED, use RIL_REQUEST_GET_ACTIVITY_INFO
  * Sent when the DC_RT_STATE changes but the time
  * between these messages must not be less than the
  * value set by RIL_REQUEST_SET_DC_RT_RATE.
@@ -4936,6 +5049,16 @@ typedef struct {
  */
 #define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
 
+/**
+ * RIL_UNSOL_LCEDATA_RECV
+ *
+ * Called when there is an incoming Link Capacity Estimate (LCE) info report.
+ *
+ * "data" is the RIL_LceDataInfo structure.
+ *
+ */
+#define RIL_UNSOL_LCEDATA_RECV 1045
+
 /***********************************************************************/
 
 
index 30731e9..3f1d3e8 100644 (file)
@@ -5,7 +5,9 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
     ril.cpp \
-    ril_event.cpp
+    ril_event.cpp\
+    RilSocket.cpp \
+    RilSapSocket.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
     liblog \
@@ -13,7 +15,10 @@ LOCAL_SHARED_LIBRARIES := \
     libbinder \
     libcutils \
     libhardware_legacy \
-    librilutils
+    librilutils \
+
+LOCAL_STATIC_LIBRARIES := \
+    libprotobuf-c-nano-enable_malloc \
 
 #LOCAL_CFLAGS := -DANDROID_MULTI_SIM -DDSDA_RILD1
 
@@ -21,8 +26,14 @@ ifeq ($(SIM_COUNT), 2)
     LOCAL_CFLAGS += -DANDROID_SIM_COUNT_2
 endif
 
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADER)/librilutils
+LOCAL_C_INCLUDES += external/nanopb-c
+
 LOCAL_MODULE:= libril
 
+LOCAL_COPY_HEADERS_TO := libril
+LOCAL_COPY_HEADERS := ril_ex.h
+
 include $(BUILD_SHARED_LIBRARY)
 
 
@@ -37,7 +48,8 @@ LOCAL_SRC_FILES:= \
 LOCAL_STATIC_LIBRARIES := \
     libutils_static \
     libcutils \
-    librilutils_static
+    librilutils_static \
+    libprotobuf-c-nano-enable_malloc
 
 LOCAL_CFLAGS :=
 
diff --git a/libril/RilSapSocket.cpp b/libril/RilSapSocket.cpp
new file mode 100644 (file)
index 0000000..0e80d70
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+* 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>
+#include <errno.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 = (uint8_t*)malloc(buffer_size);
+        if (!buffer) {
+            RLOGE("sendResponse: OOM");
+            pthread_mutex_unlock(&write_lock);
+            return;
+        }
+        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));
+        }
+        free(buffer);
+    } 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 = (uint8_t*)malloc(buffer_size);
+        if (!buffer) {
+            RLOGE("sendDisconnect: OOM");
+            return;
+        }
+        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);
+        }
+        free(buffer);
+    }
+}
+
+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/libril/RilSapSocket.h b/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/libril/RilSocket.cpp b/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/libril/RilSocket.h b/libril/RilSocket.h
new file mode 100644 (file)
index 0000000..1539c11
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+* 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;
+
+extern "C" void *ril_socket_process_requests_loop(void *arg);
+
+/**
+ * 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 a1105b4..4424561 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"
@@ -65,6 +64,8 @@ namespace android {
 
 #define ANDROID_WAKE_LOCK_NAME "radio-interface"
 
+#define ANDROID_WAKE_LOCK_SECS 0
+#define ANDROID_WAKE_LOCK_USECS 200000
 
 #define PROPERTY_RIL_IMPL "gsm.version.ril-impl"
 
@@ -90,6 +91,9 @@ namespace android {
 // request, response, and unsolicited msg print macro
 #define PRINTBUF_SIZE 8096
 
+// Enable verbose logging
+#define VDBG 0
+
 // Enable RILC log
 #define RILC_LOG 0
 
@@ -148,17 +152,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);
@@ -225,7 +218,7 @@ static struct ril_event s_wake_timeout_event;
 static struct ril_event s_debug_event;
 
 
-static const struct timeval TIMEVAL_WAKE_TIMEOUT = {1,0};
+static const struct timeval TIMEVAL_WAKE_TIMEOUT = {ANDROID_WAKE_LOCK_SECS,ANDROID_WAKE_LOCK_USECS};
 
 
 static pthread_mutex_t s_startupMutex = PTHREAD_MUTEX_INITIALIZER;
@@ -279,6 +272,7 @@ static void dispatchSimAuthentication(Parcel &p, RequestInfo *pRI);
 static void dispatchDataProfile(Parcel &p, RequestInfo *pRI);
 static void dispatchRadioCapability(Parcel &p, RequestInfo *pRI);
 static int responseInts(Parcel &p, void *response, size_t responselen);
+static int responseFailCause(Parcel &p, void *response, size_t responselen);
 static int responseStrings(Parcel &p, void *response, size_t responselen);
 static int responseString(Parcel &p, void *response, size_t responselen);
 static int responseVoid(Parcel &p, void *response, size_t responselen);
@@ -306,6 +300,9 @@ static int responseHardwareConfig(Parcel &p, void *response, size_t responselen)
 static int responseDcRtInfo(Parcel &p, void *response, size_t responselen);
 static int responseRadioCapability(Parcel &p, void *response, size_t responselen);
 static int responseSSData(Parcel &p, void *response, size_t responselen);
+static int responseLceStatus(Parcel &p, void *response, size_t responselen);
+static int responseLceData(Parcel &p, void *response, size_t responselen);
+static int responseActivityData(Parcel &p, void *response, size_t responselen);
 
 static int decodeVoiceRadioTechnology (RIL_RadioState radioState);
 static int decodeCdmaSubscriptionSource (RIL_RadioState radioState);
@@ -315,10 +312,10 @@ static bool isServiceTypeCfQuery(RIL_SsServiceType serType, RIL_SsRequestType re
 
 #ifdef RIL_SHLIB
 #if defined(ANDROID_MULTI_SIM)
-extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
+extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
                                 size_t datalen, RIL_SOCKET_ID socket_id);
 #else
-extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
+extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
                                 size_t datalen);
 #endif
 #endif
@@ -371,7 +368,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);
 }
 
@@ -710,6 +707,7 @@ dispatchSmsWrite (Parcel &p, RequestInfo *pRI) {
     int32_t t;
     status_t status;
 
+    RLOGD("dispatchSmsWrite");
     memset (&args, 0, sizeof(args));
 
     status = p.readInt32(&t);
@@ -762,6 +760,7 @@ dispatchDial (Parcel &p, RequestInfo *pRI) {
     int32_t uusPresent;
     status_t status;
 
+    RLOGD("dispatchDial");
     memset (&dial, 0, sizeof(dial));
 
     dial.address = strdupReadString(p);
@@ -866,6 +865,9 @@ dispatchSIM_IO (Parcel &p, RequestInfo *pRI) {
     int size;
     status_t status;
 
+#if VDBG
+    RLOGD("dispatchSIM_IO");
+#endif
     memset (&simIO, 0, sizeof(simIO));
 
     // note we only check status at the end
@@ -943,6 +945,9 @@ dispatchSIM_APDU (Parcel &p, RequestInfo *pRI) {
     status_t status;
     RIL_SIM_APDU apdu;
 
+#if VDBG
+    RLOGD("dispatchSIM_APDU");
+#endif
     memset (&apdu, 0, sizeof(RIL_SIM_APDU));
 
     // Note we only check status at the end. Any single failure leads to
@@ -1012,6 +1017,7 @@ dispatchCallForward(Parcel &p, RequestInfo *pRI) {
     int32_t t;
     status_t status;
 
+    RLOGD("dispatchCallForward");
     memset (&cff, 0, sizeof(cff));
 
     // note we only check status at the end
@@ -1186,7 +1192,7 @@ static void
 dispatchCdmaSms(Parcel &p, RequestInfo *pRI) {
     RIL_CDMA_SMS_Message rcsm;
 
-    ALOGD("dispatchCdmaSms");
+    RLOGD("dispatchCdmaSms");
     if (NO_ERROR != constructCdmaSms(p, pRI, rcsm)) {
         goto invalid;
     }
@@ -1209,7 +1215,7 @@ dispatchImsCdmaSms(Parcel &p, RequestInfo *pRI, uint8_t retry, int32_t messageRe
     RIL_IMS_SMS_Message rism;
     RIL_CDMA_SMS_Message rcsm;
 
-    ALOGD("dispatchImsCdmaSms: retry=%d, messageRef=%d", retry, messageRef);
+    RLOGD("dispatchImsCdmaSms: retry=%d, messageRef=%d", retry, messageRef);
 
     if (NO_ERROR != constructCdmaSms(p, pRI, rcsm)) {
         goto invalid;
@@ -1243,7 +1249,7 @@ dispatchImsGsmSms(Parcel &p, RequestInfo *pRI, uint8_t retry, int32_t messageRef
     status_t status;
     size_t datalen;
     char **pStrings;
-    ALOGD("dispatchImsGsmSms: retry=%d, messageRef=%d", retry, messageRef);
+    RLOGD("dispatchImsGsmSms: retry=%d, messageRef=%d", retry, messageRef);
 
     status = p.readInt32 (&countStrings);
 
@@ -1316,7 +1322,7 @@ dispatchImsSms(Parcel &p, RequestInfo *pRI) {
     uint8_t retry;
     int32_t messageRef;
 
-    ALOGD("dispatchImsSms");
+    RLOGD("dispatchImsSms");
     if (status != NO_ERROR) {
         goto invalid;
     }
@@ -1355,6 +1361,7 @@ dispatchCdmaSmsAck(Parcel &p, RequestInfo *pRI) {
     status_t status;
     int32_t digitCount;
 
+    RLOGD("dispatchCdmaSmsAck");
     memset(&rcsa, 0, sizeof(rcsa));
 
     status = p.readInt32(&t);
@@ -2058,7 +2065,9 @@ blockingWrite(int fd, const void *buffer, size_t len) {
             return -1;
         }
     }
-
+#if VDBG
+    RLOGE("RIL Response bytes written:%d", writeOffset);
+#endif
     return 0;
 }
 
@@ -2069,7 +2078,9 @@ sendResponseRaw (const void *data, size_t dataSize, RIL_SOCKET_ID socket_id) {
     uint32_t header;
     pthread_mutex_t * writeMutexHook = &s_writeMutex;
 
+#if VDBG
     RLOGE("Send Response to %s", rilSocketIdToString(socket_id));
+#endif
 
 #if (SIM_COUNT >= 2)
     if (socket_id == RIL_SOCKET_2) {
@@ -2162,6 +2173,40 @@ responseInts(Parcel &p, void *response, size_t responselen) {
     return 0;
 }
 
+// Response is an int or RIL_LastCallFailCauseInfo.
+// Currently, only Shamu plans to use RIL_LastCallFailCauseInfo.
+// TODO(yjl): Let all implementations use RIL_LastCallFailCauseInfo.
+static int responseFailCause(Parcel &p, void *response, size_t responselen) {
+    if (response == NULL && responselen != 0) {
+        RLOGE("invalid response: NULL");
+        return RIL_ERRNO_INVALID_RESPONSE;
+    }
+
+    if (responselen == sizeof(int)) {
+      startResponse;
+      int *p_int = (int *) response;
+      appendPrintBuf("%s%d,", printBuf, p_int[0]);
+      p.writeInt32(p_int[0]);
+      removeLastChar;
+      closeResponse;
+    } else if (responselen == sizeof(RIL_LastCallFailCauseInfo)) {
+      startResponse;
+      RIL_LastCallFailCauseInfo *p_fail_cause_info = (RIL_LastCallFailCauseInfo *) response;
+      appendPrintBuf("%s[cause_code=%d,vendor_cause=%s]", printBuf, p_fail_cause_info->cause_code,
+                     p_fail_cause_info->vendor_cause);
+      p.writeInt32(p_fail_cause_info->cause_code);
+      writeStringToParcel(p, p_fail_cause_info->vendor_cause);
+      removeLastChar;
+      closeResponse;
+    } else {
+      RLOGE("responseFailCause: invalid response length %d expected an int or "
+            "RIL_LastCallFailCauseInfo", (int)responselen);
+      return RIL_ERRNO_INVALID_RESPONSE;
+    }
+
+    return 0;
+}
+
 /** response is a char **, pointing to an array of char *'s
     The parcel will begin with the version */
 static int responseStringsWithVersion(int version, Parcel &p, void *response, size_t responselen) {
@@ -3577,6 +3622,90 @@ static int responseDcRtInfo(Parcel &p, void *response, size_t responselen)
     return 0;
 }
 
+static int responseLceStatus(Parcel &p, void *response, size_t responselen) {
+  if (response == NULL || responselen != sizeof(RIL_LceStatusInfo)) {
+    if (response == NULL) {
+      RLOGE("invalid response: NULL");
+    }
+    else {
+      RLOGE("responseLceStatus: invalid response length %d expecting len: d%",
+            sizeof(RIL_LceStatusInfo), responselen);
+    }
+    return RIL_ERRNO_INVALID_RESPONSE;
+  }
+
+  RIL_LceStatusInfo *p_cur = (RIL_LceStatusInfo *)response;
+  p.write((void *)p_cur, 1);  // p_cur->lce_status takes one byte.
+  p.writeInt32(p_cur->actual_interval_ms);
+
+  startResponse;
+  appendPrintBuf("LCE Status: %d, actual_interval_ms: %d",
+                 p_cur->lce_status, p_cur->actual_interval_ms);
+  closeResponse;
+
+  return 0;
+}
+
+static int responseLceData(Parcel &p, void *response, size_t responselen) {
+  if (response == NULL || responselen != sizeof(RIL_LceDataInfo)) {
+    if (response == NULL) {
+      RLOGE("invalid response: NULL");
+    }
+    else {
+      RLOGE("responseLceData: invalid response length %d expecting len: d%",
+            sizeof(RIL_LceDataInfo), responselen);
+    }
+    return RIL_ERRNO_INVALID_RESPONSE;
+  }
+
+  RIL_LceDataInfo *p_cur = (RIL_LceDataInfo *)response;
+  p.writeInt32(p_cur->last_hop_capacity_kbps);
+
+  /* p_cur->confidence_level and p_cur->lce_suspended take 1 byte each.*/
+  p.write((void *)&(p_cur->confidence_level), 1);
+  p.write((void *)&(p_cur->lce_suspended), 1);
+
+  startResponse;
+  appendPrintBuf("LCE info received: capacity %d confidence level %d
+                  and suspended %d",
+                  p_cur->last_hop_capacity_kbps, p_cur->confidence_level,
+                  p_cur->lce_suspended);
+  closeResponse;
+
+  return 0;
+}
+
+static int responseActivityData(Parcel &p, void *response, size_t responselen) {
+  if (response == NULL || responselen != sizeof(RIL_ActivityStatsInfo)) {
+    if (response == NULL) {
+      RLOGE("invalid response: NULL");
+    }
+    else {
+      RLOGE("responseActivityData: invalid response length %d expecting len: d%",
+            sizeof(RIL_ActivityStatsInfo), responselen);
+    }
+    return RIL_ERRNO_INVALID_RESPONSE;
+  }
+
+  RIL_ActivityStatsInfo *p_cur = (RIL_ActivityStatsInfo *)response;
+  p.writeInt32(p_cur->sleep_mode_time_ms);
+  p.writeInt32(p_cur->idle_mode_time_ms);
+  for(int i = 0; i < RIL_NUM_TX_POWER_LEVELS; i++) {
+    p.writeInt32(p_cur->tx_mode_time_ms[i]);
+  }
+  p.writeInt32(p_cur->rx_mode_time_ms);
+
+  startResponse;
+  appendPrintBuf("Modem activity info received: sleep_mode_time_ms %d idle_mode_time_ms %d
+                  tx_mode_time_ms %d %d %d %d %d and rx_mode_time_ms %d",
+                  p_cur->sleep_mode_time_ms, p_cur->idle_mode_time_ms, p_cur->tx_mode_time_ms[0],
+                  p_cur->tx_mode_time_ms[1], p_cur->tx_mode_time_ms[2], p_cur->tx_mode_time_ms[3],
+                  p_cur->tx_mode_time_ms[4], p_cur->rx_mode_time_ms);
+   closeResponse;
+
+  return 0;
+}
+
 /**
  * A write on the wakeup fd is done just to pop us out of select()
  * We empty the buffer here and then ril_event will reset the timers on the
@@ -3723,9 +3852,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);
 
@@ -3734,15 +3873,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;
     }
 
@@ -3758,7 +3909,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);
@@ -3771,17 +3922,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);
@@ -3790,20 +3948,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));
-
-    p_info->fdCommand = fdCommand;
+    if(NULL == sapSocket) {
+        RLOGI("libril: new connection to %s", rilSocketIdToString(p_info->socket_id));
 
-    p_rs = record_stream_new(p_info->fdCommand, MAX_COMMAND_BYTES);
+        p_info->fdCommand = fdCommand;
+        p_rs = record_stream_new(p_info->fdCommand, MAX_COMMAND_BYTES);
+        p_info->p_rs = p_rs;
 
-    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);
+
+        onNewCommandConnect(p_info->socket_id);
+    } else {
+        RLOGI("libril: new connection");
 
-    rilEventAddWakeup (p_info->commands_event);
+        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);
 
-    onNewCommandConnect(p_info->socket_id);
+        rilEventAddWakeup(sapSocket->getCallbackEvent());
+        sapSocket->onNewCommandConnect();
+    }
 }
 
 static void freeDebugCallbackArgs(int number, char **args) {
@@ -4255,7 +4423,7 @@ RIL_register (const RIL_RadioFunctions *callbacks) {
 
     char rildebug[MAX_DEBUG_SOCKET_NAME_LENGTH] = SOCKET_NAME_RIL_DEBUG;
     if (inst != NULL) {
-        strncat(rildebug, inst, MAX_DEBUG_SOCKET_NAME_LENGTH);
+        strlcat(rildebug, inst, MAX_DEBUG_SOCKET_NAME_LENGTH);
     }
 
     s_fdDebug = android_get_control_socket(rildebug);
@@ -4280,6 +4448,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;
@@ -4362,7 +4557,9 @@ RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responsel
     }
 #endif
 #endif
+#if VDBG
     RLOGD("RequestComplete, %s", rilSocketIdToString(socket_id));
+#endif
 
     if (pRI->local > 0) {
         // Locally issued command...void only!
@@ -4428,11 +4625,7 @@ static void
 wakeTimeoutCallback (void *param) {
     // We're using "param != NULL" as a cancellation mechanism
     if (param == NULL) {
-        //RLOGD("wakeTimeout: releasing wake lock");
-
         releaseWakeLock();
-    } else {
-        //RLOGD("wakeTimeout: releasing wake lock CANCELLED");
     }
 }
 
@@ -4556,11 +4749,11 @@ processRadioState(RIL_RadioState newRadioState, RIL_SOCKET_ID socket_id) {
 
 #if defined(ANDROID_MULTI_SIM)
 extern "C"
-void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
+void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
                                 size_t datalen, RIL_SOCKET_ID socket_id)
 #else
 extern "C"
-void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
+void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
                                 size_t datalen)
 #endif
 {
@@ -4648,7 +4841,9 @@ void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
         break;
     }
 
+#if VDBG
     RLOGI("%s UNSOLICITED: %s length:%d", rilSocketIdToString(soc_id), requestToString(unsolResponse), p.dataSize());
+#endif
     ret = sendResponse(p, soc_id);
     if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
 
@@ -4990,3 +5185,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/libril/rilSocketQueue.h b/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;
+    }
+}
index 074e822..163aa46 100644 (file)
@@ -32,7 +32,7 @@
     {RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, dispatchVoid, responseVoid},
     {RIL_REQUEST_CONFERENCE, dispatchVoid, responseVoid},
     {RIL_REQUEST_UDUB, dispatchVoid, responseVoid},
-    {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, dispatchVoid, responseInts},
+    {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, dispatchVoid, responseFailCause},
     {RIL_REQUEST_SIGNAL_STRENGTH, dispatchVoid, responseRilSignalStrength},
     {RIL_REQUEST_VOICE_REGISTRATION_STATE, dispatchVoid, responseStrings},
     {RIL_REQUEST_DATA_REGISTRATION_STATE, dispatchVoid, responseStrings},
     {RIL_REQUEST_SHUTDOWN, dispatchVoid, responseVoid},
     {RIL_REQUEST_GET_RADIO_CAPABILITY, dispatchVoid, responseRadioCapability},
     {RIL_REQUEST_SET_RADIO_CAPABILITY, dispatchRadioCapability, responseRadioCapability},
+    {RIL_REQUEST_START_LCE, dispatchInts, responseLceStatus},
+    {RIL_REQUEST_STOP_LCE, dispatchVoid, responseLceStatus},
+    {RIL_REQUEST_PULL_LCEDATA, dispatchVoid, responseLceData},
+    {RIL_REQUEST_GET_ACTIVITY_INFO, dispatchVoid, responseActivityData},
index 9d2954e..84b8b72 100644 (file)
@@ -95,14 +95,10 @@ static void dump_event(struct ril_event * ev)
 
 static void getNow(struct timeval * tv)
 {
-#ifdef HAVE_POSIX_CLOCKS
     struct timespec ts;
     clock_gettime(CLOCK_MONOTONIC, &ts);
     tv->tv_sec = ts.tv_sec;
     tv->tv_usec = ts.tv_nsec/1000;
-#else
-    gettimeofday(tv, NULL);
-#endif
 }
 
 static void init_list(struct ril_event * list)
@@ -124,18 +120,20 @@ static void addToList(struct ril_event * ev, struct ril_event * list)
 
 static void removeFromList(struct ril_event * ev)
 {
-    dlog("~~~~ Removing event ~~~~");
+    dlog("~~~~ +removeFromList ~~~~");
     dump_event(ev);
 
     ev->next->prev = ev->prev;
     ev->prev->next = ev->next;
     ev->next = NULL;
     ev->prev = NULL;
+    dlog("~~~~ -removeFromList ~~~~");
 }
 
 
 static void removeWatch(struct ril_event * ev, int index)
 {
+    dlog("~~~~ +removeWatch ~~~~");
     watch_table[index] = NULL;
     ev->index = -1;
 
@@ -154,6 +152,7 @@ static void removeWatch(struct ril_event * ev, int index)
         nfds = n + 1;
         dlog("~~~~ nfds = %d ~~~~", nfds);
     }
+    dlog("~~~~ -removeWatch ~~~~");
 }
 
 static void processTimeouts()
diff --git a/libril/ril_ex.h b/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
index 6ea7157..eb9e12d 100755 (executable)
@@ -59,3 +59,4 @@
     {RIL_UNSOL_RADIO_CAPABILITY, responseRadioCapability, WAKE_PARTIAL},
     {RIL_UNSOL_ON_SS, responseSSData, WAKE_PARTIAL},
     {RIL_UNSOL_STK_CC_ALPHA_NOTIFY, responseString, WAKE_PARTIAL},
+    {RIL_UNSOL_LCEDATA_RECV, responseLceData, WAKE_PARTIAL},
index 033a4dc..1ac00e0 100644 (file)
@@ -5,7 +5,12 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
     librilutils.c \
-    record_stream.c
+    record_stream.c \
+    proto/sap-api.proto \
+
+LOCAL_C_INCLUDES += external/nanopb-c/ \
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nanopb-c-enable_malloc
 
 LOCAL_CFLAGS :=
 
@@ -20,12 +25,26 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
     librilutils.c \
-    record_stream.c
+    record_stream.c \
+    proto/sap-api.proto \
 
-LOCAL_STATIC_LIBRARIES :=
+LOCAL_C_INCLUDES += external/nanopb-c/ \
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nanopb-c-enable_malloc
 
 LOCAL_CFLAGS :=
 
 LOCAL_MODULE:= librilutils_static
 
 include $(BUILD_STATIC_LIBRARY)
+
+# Create java protobuf code
+
+include $(CLEAR_VARS)
+
+src_proto := $(LOCAL_PATH)
+LOCAL_MODULE := sap-api-java-static
+LOCAL_SRC_FILES := proto/sap-api.proto
+LOCAL_PROTOC_OPTIMIZE_TYPE := micro
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/librilutils/proto/sap-api.options b/librilutils/proto/sap-api.options
new file mode 100644 (file)
index 0000000..f76ba93
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+MsgHeader.payload                 type:FT_POINTER
+RIL_SIM_SAP_APDU_REQ.command      type:FT_POINTER
+RIL_SIM_SAP_APDU_RSP.apduResponse type:FT_POINTER
+RIL_SIM_SAP_TRANSFER_ATR_RSP.atr  type:FT_POINTER
+
+#RIL_SIM_SAP_REQUEST.apdu type:FT_POINTER
+#RIL_SIM_SAP_RESPONSE.apdu type:FT_POINTER
diff --git a/librilutils/proto/sap-api.proto b/librilutils/proto/sap-api.proto
new file mode 100644 (file)
index 0000000..7a3d83b
--- /dev/null
@@ -0,0 +1,304 @@
+option java_package = "org.android.btsap";
+option java_outer_classname = "SapApi";
+
+//
+// SAP Interface to RIL
+//
+// The protocol for the binary wire format to RIL shall consist of
+// the serialized format of MsgHeader.
+// MsgHeader payload field will contain the serialized format of
+// the actual message being sent, as described by the type and id
+// fields.
+// e.g. If type = REQUEST and id == RIL_SIM_SAP_CONNECT, payload
+// will contain the serialized wire format of a
+// RIL_SIM_SAP_CONNECT_REQ message.
+//
+
+// Message Header
+// Each SAP message stream will always be prepended with a MsgHeader
+message MsgHeader {
+          required fixed32 token = 1; // generated dynamically
+          required MsgType type = 2;
+          required MsgId id = 3;
+          required Error error = 4;
+          required bytes payload = 5;
+}
+
+enum MsgType {
+        UNKNOWN = 0;
+        REQUEST = 1;
+        RESPONSE = 2;
+        UNSOL_RESPONSE = 3;
+     }
+
+enum MsgId {
+        UNKNOWN_REQ = 0;
+
+        //
+        // For MsgType: REQUEST ,MsgId: RIL_SIM_SAP_CONNECT, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_CONNECT_REQ
+        // For MsgType: RESPONSE, MsgId: RIL_SIM_SAP_CONNECT, Error:Valid errors,
+        //              Message: message RIL_SIM_SAP_CONNECT_RSP
+        //
+        RIL_SIM_SAP_CONNECT = 1;
+
+        //
+        // For MsgType: REQUEST ,MsgId: RIL_SIM_SAP_DISCONNECT, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_DISCONNECT_REQ
+        // For MsgType: RESPONSE, MsgId: RIL_SIM_SAP_DISCONNECT, Error:Valid errors,
+        //              Message: message RIL_SIM_SAP_DISCONNECT_RSP
+        // For MsgType: UNSOL_RESPONSE, MsgId: RIL_SIM_SAP_DISCONNECT, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_DISCONNECT_IND
+        //
+        RIL_SIM_SAP_DISCONNECT = 2;
+
+        //
+        // For MsgType: REQUEST ,MsgId: RIL_SIM_SAP_APDU, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_APDU_REQ
+        // For MsgType: RESPONSE, MsgId: RIL_SIM_SAP_APDU, Error:Valid errors,
+        //              Message: message RIL_SIM_SAP_APDU_RSP
+        //
+        RIL_SIM_SAP_APDU = 3;
+
+        //
+        // For MsgType: REQUEST ,MsgId: RIL_SIM_SAP_TRANSFER_ATR, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_TRANSFER_ATR_REQ
+        // For MsgType: RESPONSE, MsgId: RIL_SIM_SAP_TRANSFER_ATR, Error:Valid errors,
+        //              Message: message RIL_SIM_SAP_TRANSFER_ATR_RSP
+        //
+        RIL_SIM_SAP_TRANSFER_ATR = 4;
+
+        //
+        // For MsgType: REQUEST ,MsgId: RIL_SIM_SAP_POWER, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_POWER_REQ
+        // For MsgType: RESPONSE, MsgId: RIL_SIM_SAP_POWER, Error:Valid errors,
+        //              Message: message RIL_SIM_SAP_POWER_RSP
+        //
+        RIL_SIM_SAP_POWER = 5;
+
+        //
+        // For MsgType: REQUEST ,MsgId: RIL_SIM_SAP_RESET_SIM, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_RESET_SIM_REQ
+        // For MsgType: RESPONSE, MsgId: RIL_SIM_SAP_RESET_SIM, Error:Valid errors,
+        //              Message: message RIL_SIM_SAP_RESET_SIM_RSP
+        //
+        RIL_SIM_SAP_RESET_SIM = 6;
+
+        //
+        // For MsgType: UNSOL_RESPONSE, MsgId: RIL_SIM_SAP_STATUS, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_STATUS_IND
+        //
+        RIL_SIM_SAP_STATUS = 7;
+
+        //
+        // For MsgType: REQUEST ,MsgId: RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ
+        // For MsgType: RESPONSE, MsgId: RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS, Error:Valid errors,
+        //              Message: message RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP
+        //
+        RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS = 8;
+
+        //
+        // For MsgType: UNSOL_RESPONSE, MsgId: RIL_SIM_SAP_ERROR_RESP, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_ERROR_RSP
+        //
+        RIL_SIM_SAP_ERROR_RESP = 9;
+
+        //
+        // For MsgType: REQUEST ,MsgId: RIL_SIM_SAP_SET_TRANSFER_PROTOCOL, Error: RIL_E_UNUSED,
+        //              Message: message RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ
+        // For MsgType: RESPONSE, MsgId: RIL_SIM_SAP_SET_TRANSFER_PROTOCOL, Error:Valid errors,
+        //              Message: message RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP
+        //
+        RIL_SIM_SAP_SET_TRANSFER_PROTOCOL = 10;
+     }
+
+    enum Error {
+            RIL_E_SUCCESS = 0;
+            RIL_E_RADIO_NOT_AVAILABLE = 1;
+            RIL_E_GENERIC_FAILURE = 2;
+            RIL_E_REQUEST_NOT_SUPPORTED = 3;
+            RIL_E_CANCELLED = 4;
+            RIL_E_INVALID_PARAMETER = 5;
+            RIL_E_UNUSED = 6;
+    }
+
+// SAP 1.1 spec 5.1.1
+message RIL_SIM_SAP_CONNECT_REQ {
+    required int32 max_message_size = 1;
+}
+
+// SAP 1.1 spec 5.1.2
+message RIL_SIM_SAP_CONNECT_RSP {
+    enum Response {
+        RIL_E_SUCCESS = 0;
+        RIL_E_SAP_CONNECT_FAILURE = 1;
+        RIL_E_SAP_MSG_SIZE_TOO_LARGE = 2;
+        RIL_E_SAP_MSG_SIZE_TOO_SMALL = 3;
+        RIL_E_SAP_CONNECT_OK_CALL_ONGOING = 4;
+    }
+    required Response response = 1;
+// must be present for RIL_E_SAP_MSG_SIZE_TOO_LARGE and contain the
+// the suitable message size
+   optional int32 max_message_size = 2;
+}
+
+// SAP 1.1 spec 5.1.3
+message RIL_SIM_SAP_DISCONNECT_REQ {
+     //no params
+}
+
+
+// SAP 1.1 spec 5.1.4
+message RIL_SIM_SAP_DISCONNECT_RSP {
+    //no params
+}
+
+
+// SAP 1.1 spec 5.1.5
+message RIL_SIM_SAP_DISCONNECT_IND {
+    enum DisconnectType {
+        RIL_S_DISCONNECT_TYPE_GRACEFUL = 0;
+        RIL_S_DISCONNECT_TYPE_IMMEDIATE = 1;
+    }
+    required DisconnectType disconnectType = 1;
+}
+
+// SAP 1.1 spec 5.1.6
+message RIL_SIM_SAP_APDU_REQ { //handles both APDU and APDU7816
+    enum Type {
+        RIL_TYPE_APDU = 0;
+        RIL_TYPE_APDU7816 = 1;
+    }
+    required Type type = 1;
+    required bytes command = 2;
+}
+
+// SAP 1.1 spec 5.1.7
+message RIL_SIM_SAP_APDU_RSP { //handles both APDU and APDU7816
+    enum Type {
+        RIL_TYPE_APDU = 0;
+        RIL_TYPE_APDU7816 = 1;
+    }
+    required Type type = 1;
+    enum Response {
+        RIL_E_SUCCESS = 0;
+        RIL_E_GENERIC_FAILURE = 1;
+        RIL_E_SIM_NOT_READY = 2;
+        RIL_E_SIM_ALREADY_POWERED_OFF = 3;
+        RIL_E_SIM_ABSENT = 4;
+    }
+    required Response response = 2;
+    optional bytes apduResponse = 3;
+}
+
+// SAP 1.1 spec 5.1.8
+message RIL_SIM_SAP_TRANSFER_ATR_REQ {
+    // no params
+}
+
+// SAP 1.1 spec 5.1.9
+message RIL_SIM_SAP_TRANSFER_ATR_RSP {
+    enum Response {
+        RIL_E_SUCCESS = 0;
+        RIL_E_GENERIC_FAILURE = 1;
+        RIL_E_SIM_ALREADY_POWERED_OFF = 3;
+        RIL_E_SIM_ALREADY_POWERED_ON = 18;
+        RIL_E_SIM_ABSENT = 4;
+        RIL_E_SIM_DATA_NOT_AVAILABLE = 6;
+    }
+    required Response response = 1;
+
+    optional bytes atr = 2; //must be present on SUCCESS
+}
+
+
+// SAP 1.1 spec 5.1.10 +5.1.12
+message RIL_SIM_SAP_POWER_REQ {
+    required bool state = 1;  //true = on, False = off
+}
+
+// SAP 1.1 spec 5.1.11 +5.1.13
+message RIL_SIM_SAP_POWER_RSP {
+    enum Response {
+        RIL_E_SUCCESS = 0;
+        RIL_E_GENERIC_FAILURE = 2;
+        RIL_E_SIM_ABSENT = 11;
+        RIL_E_SIM_ALREADY_POWERED_OFF = 17;
+        RIL_E_SIM_ALREADY_POWERED_ON = 18;
+    }
+    required Response response = 1;
+}
+
+// SAP 1.1 spec 5.1.14
+message RIL_SIM_SAP_RESET_SIM_REQ {
+    // no params
+}
+
+// SAP 1.1 spec 5.1.15
+message RIL_SIM_SAP_RESET_SIM_RSP {
+    enum Response {
+        RIL_E_SUCCESS = 0;
+        RIL_E_GENERIC_FAILURE = 2;
+        RIL_E_SIM_ABSENT = 11;
+        RIL_E_SIM_NOT_READY = 16;
+        RIL_E_SIM_ALREADY_POWERED_OFF = 17;
+    }
+    required Response response = 1;
+}
+
+// SAP 1.1 spec 5.1.16
+message RIL_SIM_SAP_STATUS_IND {
+    enum Status {
+        RIL_SIM_STATUS_UNKNOWN_ERROR = 0;
+        RIL_SIM_STATUS_CARD_RESET = 1;
+        RIL_SIM_STATUS_CARD_NOT_ACCESSIBLE = 2;
+        RIL_SIM_STATUS_CARD_REMOVED = 3;
+        RIL_SIM_STATUS_CARD_INSERTED = 4;
+        RIL_SIM_STATUS_RECOVERED = 5;
+    }
+    required Status statusChange = 1;
+}
+
+// SAP 1.1 spec 5.1.17
+message RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ {
+    //no params
+
+}
+
+// SAP 1.1 spec 5.1.18
+message RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP {
+    enum Response {
+        RIL_E_SUCCESS = 0;
+        RIL_E_GENERIC_FAILURE = 2;
+        RIL_E_SIM_DATA_NOT_AVAILABLE = 6;
+    }
+    required Response response = 1;
+    optional int32 CardReaderStatus = 2;
+}
+
+// SAP 1.1 spec 5.1.19
+message RIL_SIM_SAP_ERROR_RSP {
+    //no params
+}
+
+// SAP 1.1 spec 5.1.20
+message RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ {
+    enum Protocol {
+        t0 = 0;
+        t1 = 1;
+    }
+    required Protocol protocol = 1;
+}
+
+// SAP 1.1 spec 5.1.21
+message RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP {
+    enum Response {
+        RIL_E_SUCCESS = 0;
+        RIL_E_GENERIC_FAILURE = 2;
+        RIL_E_SIM_ABSENT = 11;
+        RIL_E_SIM_NOT_READY = 16;
+        RIL_E_SIM_ALREADY_POWERED_OFF = 17;
+    }
+    required Response response = 1;
+}
index 151cda6..8aae88d 100644 (file)
@@ -27,6 +27,8 @@ endif
 LOCAL_MODULE:= rild
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/libril
+
 include $(BUILD_EXECUTABLE)
 
 # For radiooptions binary
index 8e479dc..c63da38 100644 (file)
@@ -31,6 +31,9 @@
 #include <cutils/sockets.h>
 #include <sys/capability.h>
 #include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <libril/ril_ex.h>
 
 #include <private/android_filesystem_config.h>
 #include "hardware/qemu_pipe.h"
@@ -38,9 +41,9 @@
 #define LIB_PATH_PROPERTY   "rild.libpath"
 #define LIB_ARGS_PROPERTY   "rild.libargs"
 #define MAX_LIB_ARGS        16
+#define MAX_CAP_NUM         (CAP_TO_INDEX(CAP_LAST_CAP) + 1)
 
-static void usage(const char *argv0)
-{
+static void usage(const char *argv0) {
     fprintf(stderr, "Usage: %s -l <ril impl library> [-- <args for impl library>]\n", argv0);
     exit(EXIT_FAILURE);
 }
@@ -49,20 +52,24 @@ extern char rild[MAX_SOCKET_NAME_LENGTH];
 
 extern void RIL_register (const RIL_RadioFunctions *callbacks);
 
+extern void RIL_register_socket (RIL_RadioFunctions *(*rilUimInit)
+        (const struct RIL_Env *, int, char **), RIL_SOCKET_TYPE socketType, int argc, char **argv);
+
 extern void RIL_onRequestComplete(RIL_Token t, RIL_Errno e,
-                           void *response, size_t responselen);
+        void *response, size_t responselen);
 
+extern void RIL_setRilSocketName(char *);
 
 #if defined(ANDROID_MULTI_SIM)
 extern void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
-                                size_t datalen, RIL_SOCKET_ID socket_id);
+        size_t datalen, RIL_SOCKET_ID socket_id);
 #else
 extern void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
-                                size_t datalen);
+        size_t datalen);
 #endif
 
 extern void RIL_requestTimedCallback (RIL_TimedCallback callback,
-                               void *param, const struct timeval *relativeTime);
+        void *param, const struct timeval *relativeTime);
 
 
 static struct RIL_Env s_rilEnv = {
@@ -73,8 +80,7 @@ static struct RIL_Env s_rilEnv = {
 
 extern void RIL_startEventLoop();
 
-static int make_argv(char * args, char ** argv)
-{
+static int make_argv(char * args, char ** argv) {
     // Note: reserve argv[0]
     int count = 1;
     char * tok;
@@ -93,6 +99,8 @@ static int make_argv(char * args, char ** argv)
  * Our group, cache, was set by init.
  */
 void switchUser() {
+    char debuggable[PROP_VALUE_MAX];
+
     prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
     setuid(AID_RADIO);
 
@@ -101,7 +109,7 @@ void switchUser() {
     header.version = _LINUX_CAPABILITY_VERSION_3;
     header.pid = 0;
 
-    struct __user_cap_data_struct data[2];
+    struct __user_cap_data_struct data[MAX_CAP_NUM];
     memset(&data, 0, sizeof(data));
 
     data[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
@@ -110,18 +118,32 @@ void switchUser() {
     data[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
     data[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
 
+    data[CAP_TO_INDEX(CAP_BLOCK_SUSPEND)].effective |= CAP_TO_MASK(CAP_BLOCK_SUSPEND);
+    data[CAP_TO_INDEX(CAP_BLOCK_SUSPEND)].permitted |= CAP_TO_MASK(CAP_BLOCK_SUSPEND);
+
     if (capset(&header, &data[0]) == -1) {
         RLOGE("capset failed: %s", strerror(errno));
         exit(EXIT_FAILURE);
     }
+
+    /*
+     * Debuggable build only:
+     * Set DUMPABLE that was cleared by setuid() to have tombstone on RIL crash
+     */
+    property_get("ro.debuggable", debuggable, "0");
+    if (strcmp(debuggable, "1") == 0) {
+        prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+    }
 }
 
-int main(int argc, char **argv)
-{
+int main(int argc, char **argv) {
     const char * rilLibPath = NULL;
     char **rilArgv;
     void *dlHandle;
     const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
+    const RIL_RadioFunctions *(*rilUimInit)(const struct RIL_Env *, int, char **);
+    char *err_str = NULL;
+
     const RIL_RadioFunctions *funcs;
     char libPath[PROPERTY_VALUE_MAX];
     unsigned char hasLibArgs = 0;
@@ -286,13 +308,26 @@ OpenLib:
 
     RIL_startEventLoop();
 
-    rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
+    rilInit =
+        (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))
+        dlsym(dlHandle, "RIL_Init");
 
     if (rilInit == NULL) {
         RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath);
         exit(EXIT_FAILURE);
     }
 
+    dlerror(); // Clear any previous dlerror
+    rilUimInit =
+        (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))
+        dlsym(dlHandle, "RIL_SAP_Init");
+    err_str = dlerror();
+    if (err_str) {
+        RLOGW("RIL_SAP_Init not defined or exported in %s: %s\n", rilLibPath, err_str);
+    } else if (!rilUimInit) {
+        RLOGW("RIL_SAP_Init defined as null in %s. SAP Not usable\n", rilLibPath);
+    }
+
     if (hasLibArgs) {
         rilArgv = argv + i - 1;
         argc = argc -i + 1;
@@ -318,6 +353,13 @@ OpenLib:
 
     RLOGD("RIL_Init RIL_register completed");
 
+    if (rilUimInit) {
+        RLOGD("RIL_register_socket started");
+        RIL_register_socket(rilUimInit, RIL_SAP_SOCKET, argc, rilArgv);
+    }
+
+    RLOGD("RIL_register_socket completed");
+
 done:
 
     RLOGD("RIL_Init starting sleep loop");