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;
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 {
*/
} 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,
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 */
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
*
/**
* 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
/**
* 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
*
* 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
*/
#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
/***********************************************************************/
/**
* 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.
*/
#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
+
/***********************************************************************/
LOCAL_SRC_FILES:= \
ril.cpp \
- ril_event.cpp
+ ril_event.cpp\
+ RilSocket.cpp \
+ RilSapSocket.cpp \
LOCAL_SHARED_LIBRARIES := \
liblog \
libbinder \
libcutils \
libhardware_legacy \
- librilutils
+ librilutils \
+
+LOCAL_STATIC_LIBRARIES := \
+ libprotobuf-c-nano-enable_malloc \
#LOCAL_CFLAGS := -DANDROID_MULTI_SIM -DDSDA_RILD1
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)
LOCAL_STATIC_LIBRARIES := \
libutils_static \
libcutils \
- librilutils_static
+ librilutils_static \
+ libprotobuf-c-nano-enable_malloc
LOCAL_CFLAGS :=
--- /dev/null
+/*
+* 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");
+}
--- /dev/null
+/*
+* 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*/
--- /dev/null
+/*
+* 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;
+}
--- /dev/null
+/*
+* 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
#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"
#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"
// request, response, and unsolicited msg print macro
#define PRINTBUF_SIZE 8096
+// Enable verbose logging
+#define VDBG 0
+
// Enable RILC log
#define RILC_LOG 0
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);
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;
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);
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);
#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
}
extern "C"
-void RIL_setRilSocketName(char * s) {
+void RIL_setRilSocketName(const char * s) {
strncpy(rild, s, MAX_SOCKET_NAME_LENGTH);
}
int32_t t;
status_t status;
+ RLOGD("dispatchSmsWrite");
memset (&args, 0, sizeof(args));
status = p.readInt32(&t);
int32_t uusPresent;
status_t status;
+ RLOGD("dispatchDial");
memset (&dial, 0, sizeof(dial));
dial.address = strdupReadString(p);
int size;
status_t status;
+#if VDBG
+ RLOGD("dispatchSIM_IO");
+#endif
memset (&simIO, 0, sizeof(simIO));
// note we only check status at the end
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
int32_t t;
status_t status;
+ RLOGD("dispatchCallForward");
memset (&cff, 0, sizeof(cff));
// note we only check status at the end
dispatchCdmaSms(Parcel &p, RequestInfo *pRI) {
RIL_CDMA_SMS_Message rcsm;
- ALOGD("dispatchCdmaSms");
+ RLOGD("dispatchCdmaSms");
if (NO_ERROR != constructCdmaSms(p, pRI, rcsm)) {
goto invalid;
}
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;
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);
uint8_t retry;
int32_t messageRef;
- ALOGD("dispatchImsSms");
+ RLOGD("dispatchImsSms");
if (status != NO_ERROR) {
goto invalid;
}
status_t status;
int32_t digitCount;
+ RLOGD("dispatchCdmaSmsAck");
memset(&rcsa, 0, sizeof(rcsa));
status = p.readInt32(&t);
return -1;
}
}
-
+#if VDBG
+ RLOGE("RIL Response bytes written:%d", writeOffset);
+#endif
return 0;
}
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) {
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) {
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
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);
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;
}
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);
}
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);
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) {
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);
}
+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;
}
#endif
#endif
+#if VDBG
RLOGD("RequestComplete, %s", rilSocketIdToString(socket_id));
+#endif
if (pRI->local > 0) {
// Locally issued command...void only!
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");
}
}
#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
{
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) {
}
} /* 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);
+}
--- /dev/null
+/*
+* 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;
+ }
+}
{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},
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)
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;
nfds = n + 1;
dlog("~~~~ nfds = %d ~~~~", nfds);
}
+ dlog("~~~~ -removeWatch ~~~~");
}
static void processTimeouts()
--- /dev/null
+/*
+* 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
{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},
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 :=
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)
--- /dev/null
+#
+# 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
--- /dev/null
+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;
+}
LOCAL_MODULE:= rild
LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/libril
+
include $(BUILD_EXECUTABLE)
# For radiooptions binary
#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"
#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);
}
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 = {
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;
* 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);
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);
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;
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;
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");