ril: import Oreo AOSP libril

Change-Id: I00750bad812dc263e9c74a504b48512a892376c8
diff --git a/ril/libril/sap_service.cpp b/ril/libril/sap_service.cpp
new file mode 100644
index 0000000..7bed05a
--- /dev/null
+++ b/ril/libril/sap_service.cpp
@@ -0,0 +1,958 @@
+/*
+ * Copyright (c) 2016 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 LOG_TAG "RIL_SAP"
+
+#include <android/hardware/radio/1.0/ISap.h>
+
+#include <hwbinder/IPCThreadState.h>
+#include <hwbinder/ProcessState.h>
+#include <sap_service.h>
+#include "pb_decode.h"
+#include "pb_encode.h"
+
+using namespace android::hardware::radio::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_array;
+using ::android::hardware::Void;
+using android::CommandInfo;
+using android::RequestInfo;
+using android::requestToString;
+using android::sp;
+
+struct SapImpl;
+
+#if (SIM_COUNT >= 2)
+sp<SapImpl> sapService[SIM_COUNT];
+#else
+sp<SapImpl> sapService[1];
+#endif
+
+struct SapImpl : public ISap {
+    int32_t slotId;
+    sp<ISapCallback> sapCallback;
+    RIL_SOCKET_ID rilSocketId;
+
+    Return<void> setCallback(const ::android::sp<ISapCallback>& sapCallbackParam);
+
+    Return<void> connectReq(int32_t token, int32_t maxMsgSize);
+
+    Return<void> disconnectReq(int32_t token);
+
+    Return<void> apduReq(int32_t token, SapApduType type, const hidl_vec<uint8_t>& command);
+
+    Return<void> transferAtrReq(int32_t token);
+
+    Return<void> powerReq(int32_t token, bool state);
+
+    Return<void> resetSimReq(int32_t token);
+
+    Return<void> transferCardReaderStatusReq(int32_t token);
+
+    Return<void> setTransferProtocolReq(int32_t token, SapTransferProtocol transferProtocol);
+
+    MsgHeader* createMsgHeader(MsgId msgId, int32_t token);
+
+    Return<void> addPayloadAndDispatchRequest(MsgHeader *msg, uint16_t reqLen, uint8_t *reqPtr);
+
+    void sendFailedResponse(MsgId msgId, int32_t token, int numPointers, ...);
+
+    void checkReturnStatus(Return<void>& ret);
+};
+
+void SapImpl::checkReturnStatus(Return<void>& ret) {
+    if (ret.isOk() == false) {
+        RLOGE("checkReturnStatus: unable to call response/indication callback: %s",
+                ret.description().c_str());
+        // Remote process (SapRilReceiver.java) hosting the callback must be dead. Reset the
+        // callback object; there's no other recovery to be done here. When the client process is
+        // back up, it will call setCallback()
+        sapCallback = NULL;
+    }
+}
+
+Return<void> SapImpl::setCallback(const ::android::sp<ISapCallback>& sapCallbackParam) {
+    RLOGD("SapImpl::setCallback for slotId %d", slotId);
+    sapCallback = sapCallbackParam;
+    return Void();
+}
+
+MsgHeader* SapImpl::createMsgHeader(MsgId msgId, int32_t token) {
+    // Memory for msg will be freed by RilSapSocket::onRequestComplete()
+    MsgHeader *msg = (MsgHeader *)calloc(1, sizeof(MsgHeader));
+    if (msg == NULL) {
+        return NULL;
+    }
+    msg->token = token;
+    msg->type = MsgType_REQUEST;
+    msg->id = msgId;
+    msg->error = Error_RIL_E_SUCCESS;
+    return msg;
+}
+
+Return<void> SapImpl::addPayloadAndDispatchRequest(MsgHeader *msg, uint16_t reqLen,
+        uint8_t *reqPtr) {
+    msg->payload = (pb_bytes_array_t *)malloc(sizeof(pb_bytes_array_t) - 1 + reqLen);
+    if (msg->payload == NULL) {
+        sendFailedResponse(msg->id, msg->token, 2, reqPtr, msg);
+        return Void();
+    }
+    msg->payload->size = reqLen;
+    memcpy(msg->payload->bytes, reqPtr, reqLen);
+
+    RilSapSocket *sapSocket = RilSapSocket::getSocketById(rilSocketId);
+    if (sapSocket) {
+        RLOGD("SapImpl::addPayloadAndDispatchRequest: calling dispatchRequest");
+        sapSocket->dispatchRequest(msg);
+    } else {
+        RLOGE("SapImpl::addPayloadAndDispatchRequest: sapSocket is null");
+        sendFailedResponse(msg->id, msg->token, 3, msg->payload, reqPtr, msg);
+        return Void();
+    }
+    free(msg->payload);
+    free(reqPtr);
+    return Void();
+}
+
+void SapImpl::sendFailedResponse(MsgId msgId, int32_t token, int numPointers, ...) {
+    va_list ap;
+    va_start(ap, numPointers);
+    for (int i = 0; i < numPointers; i++) {
+        void *ptr = va_arg(ap, void *);
+        if (ptr) free(ptr);
+    }
+    va_end(ap);
+    Return<void> retStatus;
+    switch(msgId) {
+        case MsgId_RIL_SIM_SAP_CONNECT:
+            retStatus = sapCallback->connectResponse(token, SapConnectRsp::CONNECT_FAILURE, 0);
+            break;
+
+        case MsgId_RIL_SIM_SAP_DISCONNECT:
+            retStatus = sapCallback->disconnectResponse(token);
+            break;
+
+        case MsgId_RIL_SIM_SAP_APDU: {
+            hidl_vec<uint8_t> apduRsp;
+            retStatus = sapCallback->apduResponse(token, SapResultCode::GENERIC_FAILURE, apduRsp);
+            break;
+        }
+
+        case MsgId_RIL_SIM_SAP_TRANSFER_ATR: {
+            hidl_vec<uint8_t> atr;
+            retStatus = sapCallback->transferAtrResponse(token, SapResultCode::GENERIC_FAILURE,
+                    atr);
+            break;
+        }
+
+        case MsgId_RIL_SIM_SAP_POWER:
+            retStatus = sapCallback->powerResponse(token, SapResultCode::GENERIC_FAILURE);
+            break;
+
+        case MsgId_RIL_SIM_SAP_RESET_SIM:
+            retStatus = sapCallback->resetSimResponse(token, SapResultCode::GENERIC_FAILURE);
+            break;
+
+        case MsgId_RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS:
+            retStatus = sapCallback->transferCardReaderStatusResponse(token,
+                    SapResultCode::GENERIC_FAILURE, 0);
+            break;
+
+        case MsgId_RIL_SIM_SAP_SET_TRANSFER_PROTOCOL:
+            retStatus = sapCallback->transferProtocolResponse(token, SapResultCode::NOT_SUPPORTED);
+            break;
+
+        default:
+            return;
+    }
+    sapService[slotId]->checkReturnStatus(retStatus);
+}
+
+Return<void> SapImpl::connectReq(int32_t token, int32_t maxMsgSize) {
+    RLOGD("SapImpl::connectReq");
+    MsgHeader *msg = createMsgHeader(MsgId_RIL_SIM_SAP_CONNECT, token);
+    if (msg == NULL) {
+        RLOGE("SapImpl::connectReq: Error allocating memory for msg");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_CONNECT, token, 0);
+        return Void();
+    }
+
+    /***** Encode RIL_SIM_SAP_CONNECT_REQ *****/
+    RIL_SIM_SAP_CONNECT_REQ req;
+    memset(&req, 0, sizeof(RIL_SIM_SAP_CONNECT_REQ));
+    req.max_message_size = maxMsgSize;
+
+    size_t encodedSize = 0;
+    if (!pb_get_encoded_size(&encodedSize, RIL_SIM_SAP_CONNECT_REQ_fields, &req)) {
+        RLOGE("SapImpl::connectReq: Error getting encoded size for RIL_SIM_SAP_CONNECT_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_CONNECT, token, 1, msg);
+        return Void();
+    }
+
+    uint8_t *buffer = (uint8_t *)calloc(1, encodedSize);
+    if (buffer == NULL) {
+        RLOGE("SapImpl::connectReq: Error allocating memory for buffer");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_CONNECT, token, 1, msg);
+        return Void();
+    }
+    pb_ostream_t stream = pb_ostream_from_buffer(buffer, encodedSize);
+
+    RLOGD("SapImpl::connectReq calling pb_encode");
+    if (!pb_encode(&stream, RIL_SIM_SAP_CONNECT_REQ_fields, &req)) {
+        RLOGE("SapImpl::connectReq: Error encoding RIL_SIM_SAP_CONNECT_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_CONNECT, token, 2, buffer, msg);
+        return Void();
+    }
+    /***** Encode RIL_SIM_SAP_CONNECT_REQ done *****/
+
+    /* encoded req is payload */
+    return addPayloadAndDispatchRequest(msg, stream.bytes_written, buffer);
+}
+
+Return<void> SapImpl::disconnectReq(int32_t token) {
+    RLOGD("SapImpl::disconnectReq");
+    MsgHeader *msg = createMsgHeader(MsgId_RIL_SIM_SAP_DISCONNECT, token);
+    if (msg == NULL) {
+        RLOGE("SapImpl::disconnectReq: Error allocating memory for msg");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_DISCONNECT, token, 0);
+        return Void();
+    }
+
+    /***** Encode RIL_SIM_SAP_DISCONNECT_REQ *****/
+    RIL_SIM_SAP_DISCONNECT_REQ req;
+    memset(&req, 0, sizeof(RIL_SIM_SAP_DISCONNECT_REQ));
+
+    size_t encodedSize = 0;
+    if (!pb_get_encoded_size(&encodedSize, RIL_SIM_SAP_DISCONNECT_REQ_fields, &req)) {
+        RLOGE("SapImpl::disconnectReq: Error getting encoded size for RIL_SIM_SAP_DISCONNECT_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_DISCONNECT, token, 1, msg);
+        return Void();
+    }
+
+    uint8_t *buffer = (uint8_t *)calloc(1, encodedSize);
+    if (buffer == NULL) {
+        RLOGE("SapImpl::disconnectReq: Error allocating memory for buffer");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_DISCONNECT, token, 1, msg);
+        return Void();
+    }
+
+    pb_ostream_t stream = pb_ostream_from_buffer(buffer, encodedSize);
+
+    RLOGD("SapImpl::disconnectReq calling pb_encode");
+    if (!pb_encode(&stream, RIL_SIM_SAP_DISCONNECT_REQ_fields, &req)) {
+        RLOGE("SapImpl::disconnectReq: Error encoding RIL_SIM_SAP_DISCONNECT_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_DISCONNECT, token, 2, buffer, msg);
+        return Void();
+    }
+    /***** Encode RIL_SIM_SAP_DISCONNECT_REQ done *****/
+
+    /* encoded req is payload */
+    return addPayloadAndDispatchRequest(msg, stream.bytes_written, buffer);
+}
+
+Return<void> SapImpl::apduReq(int32_t token, SapApduType type, const hidl_vec<uint8_t>& command) {
+    RLOGD("SapImpl::apduReq");
+    MsgHeader *msg = createMsgHeader(MsgId_RIL_SIM_SAP_APDU, token);
+    if (msg == NULL) {
+        RLOGE("SapImpl::apduReq: Error allocating memory for msg");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_APDU, token, 0);
+        return Void();
+    }
+
+    /***** Encode RIL_SIM_SAP_APDU_REQ *****/
+    RIL_SIM_SAP_APDU_REQ req;
+    memset(&req, 0, sizeof(RIL_SIM_SAP_APDU_REQ));
+    req.type = (RIL_SIM_SAP_APDU_REQ_Type)type;
+
+    if (command.size() > 0) {
+        req.command = (pb_bytes_array_t *)malloc(sizeof(pb_bytes_array_t) - 1 + command.size());
+        if (req.command == NULL) {
+            RLOGE("SapImpl::apduReq: Error allocating memory for req.command");
+            sendFailedResponse(MsgId_RIL_SIM_SAP_APDU, token, 1, msg);
+            return Void();
+        }
+        req.command->size = command.size();
+        memcpy(req.command->bytes, command.data(), command.size());
+    }
+
+    size_t encodedSize = 0;
+    if (!pb_get_encoded_size(&encodedSize, RIL_SIM_SAP_APDU_REQ_fields, &req)) {
+        RLOGE("SapImpl::apduReq: Error getting encoded size for RIL_SIM_SAP_APDU_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_APDU, token, 2, req.command, msg);
+        return Void();
+    }
+
+    uint8_t *buffer = (uint8_t *)calloc(1, encodedSize);
+    if (buffer == NULL) {
+        RLOGE("SapImpl::apduReq: Error allocating memory for buffer");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_APDU, token, 2, req.command, msg);
+        return Void();
+    }
+
+    pb_ostream_t stream = pb_ostream_from_buffer(buffer, encodedSize);
+
+    RLOGD("SapImpl::apduReq calling pb_encode");
+    if (!pb_encode(&stream, RIL_SIM_SAP_APDU_REQ_fields, &req)) {
+        RLOGE("SapImpl::apduReq: Error encoding RIL_SIM_SAP_APDU_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_APDU, token, 3, req.command, buffer, msg);
+        return Void();
+    }
+    /***** Encode RIL_SIM_SAP_APDU_REQ done *****/
+
+    /* encoded req is payload */
+    return addPayloadAndDispatchRequest(msg, stream.bytes_written, buffer);
+}
+
+Return<void> SapImpl::transferAtrReq(int32_t token) {
+    RLOGD("SapImpl::transferAtrReq");
+    MsgHeader *msg = createMsgHeader(MsgId_RIL_SIM_SAP_TRANSFER_ATR, token);
+    if (msg == NULL) {
+        RLOGE("SapImpl::transferAtrReq: Error allocating memory for msg");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_TRANSFER_ATR, token, 0);
+        return Void();
+    }
+
+    /***** Encode RIL_SIM_SAP_TRANSFER_ATR_REQ *****/
+    RIL_SIM_SAP_TRANSFER_ATR_REQ req;
+    memset(&req, 0, sizeof(RIL_SIM_SAP_TRANSFER_ATR_REQ));
+
+    size_t encodedSize = 0;
+    if (!pb_get_encoded_size(&encodedSize, RIL_SIM_SAP_TRANSFER_ATR_REQ_fields, &req)) {
+        RLOGE("SapImpl::transferAtrReq: Error getting encoded size for "
+                "RIL_SIM_SAP_TRANSFER_ATR_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_TRANSFER_ATR, token, 1, msg);
+        return Void();
+    }
+
+    uint8_t *buffer = (uint8_t *)calloc(1, encodedSize);
+    if (buffer == NULL) {
+        RLOGE("SapImpl::transferAtrReq: Error allocating memory for buffer");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_TRANSFER_ATR, token, 1, msg);
+        return Void();
+    }
+
+    pb_ostream_t stream = pb_ostream_from_buffer(buffer, encodedSize);
+
+    RLOGD("SapImpl::transferAtrReq calling pb_encode");
+    if (!pb_encode(&stream, RIL_SIM_SAP_TRANSFER_ATR_REQ_fields, &req)) {
+        RLOGE("SapImpl::transferAtrReq: Error encoding RIL_SIM_SAP_TRANSFER_ATR_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_TRANSFER_ATR, token, 2, buffer, msg);
+        return Void();
+    }
+    /***** Encode RIL_SIM_SAP_TRANSFER_ATR_REQ done *****/
+
+    /* encoded req is payload */
+    return addPayloadAndDispatchRequest(msg, stream.bytes_written, buffer);
+}
+
+Return<void> SapImpl::powerReq(int32_t token, bool state) {
+    RLOGD("SapImpl::powerReq");
+    MsgHeader *msg = createMsgHeader(MsgId_RIL_SIM_SAP_POWER, token);
+    if (msg == NULL) {
+        RLOGE("SapImpl::powerReq: Error allocating memory for msg");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_POWER, token, 0);
+        return Void();
+    }
+
+    /***** Encode RIL_SIM_SAP_POWER_REQ *****/
+    RIL_SIM_SAP_POWER_REQ req;
+    memset(&req, 0, sizeof(RIL_SIM_SAP_POWER_REQ));
+    req.state = state;
+
+    size_t encodedSize = 0;
+    if (!pb_get_encoded_size(&encodedSize, RIL_SIM_SAP_POWER_REQ_fields, &req)) {
+        RLOGE("SapImpl::powerReq: Error getting encoded size for RIL_SIM_SAP_POWER_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_POWER, token, 1, msg);
+        return Void();
+    }
+
+    uint8_t *buffer = (uint8_t *)calloc(1, encodedSize);
+    if (buffer == NULL) {
+        RLOGE("SapImpl::powerReq: Error allocating memory for buffer");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_POWER, token, 1, msg);
+        return Void();
+    }
+
+    pb_ostream_t stream = pb_ostream_from_buffer(buffer, encodedSize);
+
+    RLOGD("SapImpl::powerReq calling pb_encode");
+    if (!pb_encode(&stream, RIL_SIM_SAP_POWER_REQ_fields, &req)) {
+        RLOGE("SapImpl::powerReq: Error encoding RIL_SIM_SAP_POWER_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_POWER, token, 2, buffer, msg);
+        return Void();
+    }
+    /***** Encode RIL_SIM_SAP_POWER_REQ done *****/
+
+    /* encoded req is payload */
+    return addPayloadAndDispatchRequest(msg, stream.bytes_written, buffer);
+}
+
+Return<void> SapImpl::resetSimReq(int32_t token) {
+    RLOGD("SapImpl::resetSimReq");
+    MsgHeader *msg = createMsgHeader(MsgId_RIL_SIM_SAP_RESET_SIM, token);
+    if (msg == NULL) {
+        RLOGE("SapImpl::resetSimReq: Error allocating memory for msg");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_RESET_SIM, token, 0);
+        return Void();
+    }
+
+    /***** Encode RIL_SIM_SAP_RESET_SIM_REQ *****/
+    RIL_SIM_SAP_RESET_SIM_REQ req;
+    memset(&req, 0, sizeof(RIL_SIM_SAP_RESET_SIM_REQ));
+
+    size_t encodedSize = 0;
+    if (!pb_get_encoded_size(&encodedSize, RIL_SIM_SAP_RESET_SIM_REQ_fields, &req)) {
+        RLOGE("SapImpl::resetSimReq: Error getting encoded size for RIL_SIM_SAP_RESET_SIM_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_RESET_SIM, token, 1, msg);
+        return Void();
+    }
+
+    uint8_t *buffer = (uint8_t *)calloc(1, encodedSize);
+    if (buffer == NULL) {
+        RLOGE("SapImpl::resetSimReq: Error allocating memory for buffer");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_RESET_SIM, token, 1, msg);
+        return Void();
+    }
+
+    pb_ostream_t stream = pb_ostream_from_buffer(buffer, encodedSize);
+
+    RLOGD("SapImpl::resetSimReq calling pb_encode");
+    if (!pb_encode(&stream, RIL_SIM_SAP_RESET_SIM_REQ_fields, &req)) {
+        RLOGE("SapImpl::resetSimReq: Error encoding RIL_SIM_SAP_RESET_SIM_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_RESET_SIM, token, 2, buffer, msg);
+        return Void();
+    }
+    /***** Encode RIL_SIM_SAP_RESET_SIM_REQ done *****/
+
+    /* encoded req is payload */
+    return addPayloadAndDispatchRequest(msg, stream.bytes_written, buffer);
+}
+
+Return<void> SapImpl::transferCardReaderStatusReq(int32_t token) {
+    RLOGD("SapImpl::transferCardReaderStatusReq");
+    MsgHeader *msg = createMsgHeader(MsgId_RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS, token);
+    if (msg == NULL) {
+        RLOGE("SapImpl::transferCardReaderStatusReq: Error allocating memory for msg");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS, token, 0);
+        return Void();
+    }
+
+    /***** Encode RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ *****/
+    RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ req;
+    memset(&req, 0, sizeof(RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ));
+
+    size_t encodedSize = 0;
+    if (!pb_get_encoded_size(&encodedSize, RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ_fields,
+            &req)) {
+        RLOGE("SapImpl::transferCardReaderStatusReq: Error getting encoded size for "
+                "RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS, token, 1, msg);
+        return Void();
+    }
+
+    uint8_t *buffer = (uint8_t *)calloc(1, encodedSize);
+    if (buffer == NULL) {
+        RLOGE("SapImpl::transferCardReaderStatusReq: Error allocating memory for buffer");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS, token, 1, msg);
+        return Void();
+    }
+
+    pb_ostream_t stream = pb_ostream_from_buffer(buffer, encodedSize);
+
+    RLOGD("SapImpl::transferCardReaderStatusReq calling pb_encode");
+    if (!pb_encode(&stream, RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ_fields, &req)) {
+        RLOGE("SapImpl::transferCardReaderStatusReq: Error encoding "
+                "RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS, token, 2, buffer, msg);
+        return Void();
+    }
+    /***** Encode RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ done *****/
+
+    /* encoded req is payload */
+    return addPayloadAndDispatchRequest(msg, stream.bytes_written, buffer);
+}
+
+Return<void> SapImpl::setTransferProtocolReq(int32_t token, SapTransferProtocol transferProtocol) {
+    RLOGD("SapImpl::setTransferProtocolReq");
+    MsgHeader *msg = createMsgHeader(MsgId_RIL_SIM_SAP_SET_TRANSFER_PROTOCOL, token);
+    if (msg == NULL) {
+        RLOGE("SapImpl::setTransferProtocolReq: Error allocating memory for msg");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_SET_TRANSFER_PROTOCOL, token, 0);
+        return Void();
+    }
+
+    /***** Encode RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ *****/
+    RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ req;
+    memset(&req, 0, sizeof(RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ));
+    req.protocol = (RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ_Protocol)transferProtocol;
+
+    size_t encodedSize = 0;
+    if (!pb_get_encoded_size(&encodedSize, RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ_fields, &req)) {
+        RLOGE("SapImpl::setTransferProtocolReq: Error getting encoded size for "
+                "RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_SET_TRANSFER_PROTOCOL, token, 1, msg);
+        return Void();
+    }
+
+    uint8_t *buffer = (uint8_t *)calloc(1, encodedSize);
+    if (buffer == NULL) {
+        RLOGE("SapImpl::setTransferProtocolReq: Error allocating memory for buffer");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_SET_TRANSFER_PROTOCOL, token, 1, msg);
+        return Void();
+    }
+
+    pb_ostream_t stream = pb_ostream_from_buffer(buffer, encodedSize);
+
+    RLOGD("SapImpl::setTransferProtocolReq calling pb_encode");
+    if (!pb_encode(&stream, RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ_fields, &req)) {
+        RLOGE("SapImpl::setTransferProtocolReq: Error encoding "
+                "RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ");
+        sendFailedResponse(MsgId_RIL_SIM_SAP_SET_TRANSFER_PROTOCOL, token, 2, buffer, msg);
+        return Void();
+    }
+    /***** Encode RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ done *****/
+
+    /* encoded req is payload */
+    return addPayloadAndDispatchRequest(msg, stream.bytes_written, buffer);
+}
+
+void *sapDecodeMessage(MsgId msgId, MsgType msgType, uint8_t *payloadPtr, size_t payloadLen) {
+    void *responsePtr = NULL;
+    bool decodeStatus = false;
+    pb_istream_t stream;
+
+    /* Create the stream */
+    stream = pb_istream_from_buffer((uint8_t *)payloadPtr, payloadLen);
+
+    /* Decode based on the message id */
+    switch (msgId)
+    {
+        case MsgId_RIL_SIM_SAP_CONNECT:
+            responsePtr = malloc(sizeof(RIL_SIM_SAP_CONNECT_RSP));
+            if (responsePtr) {
+                if (!pb_decode(&stream, RIL_SIM_SAP_CONNECT_RSP_fields, responsePtr)) {
+                    RLOGE("Error decoding RIL_SIM_SAP_CONNECT_RSP");
+                    return NULL;
+                }
+            }
+            break;
+
+        case MsgId_RIL_SIM_SAP_DISCONNECT:
+            if (msgType == MsgType_RESPONSE) {
+                responsePtr = malloc(sizeof(RIL_SIM_SAP_DISCONNECT_RSP));
+                if (responsePtr) {
+                    if (!pb_decode(&stream, RIL_SIM_SAP_DISCONNECT_RSP_fields, responsePtr)) {
+                        RLOGE("Error decoding RIL_SIM_SAP_DISCONNECT_RSP");
+                        return NULL;
+                    }
+                }
+            } else {
+                responsePtr = malloc(sizeof(RIL_SIM_SAP_DISCONNECT_IND));
+                if (responsePtr) {
+                    if (!pb_decode(&stream, RIL_SIM_SAP_DISCONNECT_IND_fields, responsePtr)) {
+                        RLOGE("Error decoding RIL_SIM_SAP_DISCONNECT_IND");
+                        return NULL;
+                    }
+                }
+            }
+            break;
+
+        case MsgId_RIL_SIM_SAP_APDU:
+            responsePtr = malloc(sizeof(RIL_SIM_SAP_APDU_RSP));
+            if (responsePtr) {
+                if (!pb_decode(&stream, RIL_SIM_SAP_APDU_RSP_fields, responsePtr)) {
+                    RLOGE("Error decoding RIL_SIM_SAP_APDU_RSP");
+                    return NULL;
+                }
+            }
+            break;
+
+        case MsgId_RIL_SIM_SAP_TRANSFER_ATR:
+            responsePtr = malloc(sizeof(RIL_SIM_SAP_TRANSFER_ATR_RSP));
+            if (responsePtr) {
+                if (!pb_decode(&stream, RIL_SIM_SAP_TRANSFER_ATR_RSP_fields, responsePtr)) {
+                    RLOGE("Error decoding RIL_SIM_SAP_TRANSFER_ATR_RSP");
+                    return NULL;
+                }
+            }
+            break;
+
+        case MsgId_RIL_SIM_SAP_POWER:
+            responsePtr = malloc(sizeof(RIL_SIM_SAP_POWER_RSP));
+            if (responsePtr) {
+                if (!pb_decode(&stream, RIL_SIM_SAP_POWER_RSP_fields, responsePtr)) {
+                    RLOGE("Error decoding RIL_SIM_SAP_POWER_RSP");
+                    return NULL;
+                }
+            }
+            break;
+
+        case MsgId_RIL_SIM_SAP_RESET_SIM:
+            responsePtr = malloc(sizeof(RIL_SIM_SAP_RESET_SIM_RSP));
+            if (responsePtr) {
+                if (!pb_decode(&stream, RIL_SIM_SAP_RESET_SIM_RSP_fields, responsePtr)) {
+                    RLOGE("Error decoding RIL_SIM_SAP_RESET_SIM_RSP");
+                    return NULL;
+                }
+            }
+            break;
+
+        case MsgId_RIL_SIM_SAP_STATUS:
+            responsePtr = malloc(sizeof(RIL_SIM_SAP_STATUS_IND));
+            if (responsePtr) {
+                if (!pb_decode(&stream, RIL_SIM_SAP_STATUS_IND_fields, responsePtr)) {
+                    RLOGE("Error decoding RIL_SIM_SAP_STATUS_IND");
+                    return NULL;
+                }
+            }
+            break;
+
+        case MsgId_RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS:
+            responsePtr = malloc(sizeof(RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP));
+            if (responsePtr) {
+                if (!pb_decode(&stream, RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP_fields,
+                        responsePtr)) {
+                    RLOGE("Error decoding RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP");
+                    return NULL;
+                }
+            }
+            break;
+
+        case MsgId_RIL_SIM_SAP_ERROR_RESP:
+            responsePtr = malloc(sizeof(RIL_SIM_SAP_ERROR_RSP));
+            if (responsePtr) {
+                if (!pb_decode(&stream, RIL_SIM_SAP_ERROR_RSP_fields, responsePtr)) {
+                    RLOGE("Error decoding RIL_SIM_SAP_ERROR_RSP");
+                    return NULL;
+                }
+            }
+            break;
+
+        case MsgId_RIL_SIM_SAP_SET_TRANSFER_PROTOCOL:
+            responsePtr = malloc(sizeof(RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP));
+            if (responsePtr) {
+                if (!pb_decode(&stream, RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP_fields,
+                        responsePtr)) {
+                    RLOGE("Error decoding RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP");
+                    return NULL;
+                }
+            }
+            break;
+
+        default:
+            break;
+    }
+    return responsePtr;
+} /* sapDecodeMessage */
+
+sp<SapImpl> getSapImpl(RilSapSocket *sapSocket) {
+    switch (sapSocket->getSocketId()) {
+        case RIL_SOCKET_1:
+            RLOGD("getSapImpl: returning sapService[0]");
+            return sapService[0];
+        #if (SIM_COUNT >= 2)
+        case RIL_SOCKET_2:
+            return sapService[1];
+        #if (SIM_COUNT >= 3)
+        case RIL_SOCKET_3:
+            return sapService[2];
+        #if (SIM_COUNT >= 4)
+        case RIL_SOCKET_4:
+            return sapService[3];
+        #endif
+        #endif
+        #endif
+        default:
+            return NULL;
+    }
+}
+
+SapResultCode convertApduResponseProtoToHal(RIL_SIM_SAP_APDU_RSP_Response responseProto) {
+    switch(responseProto) {
+        case RIL_SIM_SAP_APDU_RSP_Response_RIL_E_SUCCESS:
+            return SapResultCode::SUCCESS;
+        case RIL_SIM_SAP_APDU_RSP_Response_RIL_E_GENERIC_FAILURE:
+            return SapResultCode::GENERIC_FAILURE;
+        case RIL_SIM_SAP_APDU_RSP_Response_RIL_E_SIM_NOT_READY:
+            return SapResultCode::CARD_NOT_ACCESSSIBLE;
+        case RIL_SIM_SAP_APDU_RSP_Response_RIL_E_SIM_ALREADY_POWERED_OFF:
+            return SapResultCode::CARD_ALREADY_POWERED_OFF;
+        case RIL_SIM_SAP_APDU_RSP_Response_RIL_E_SIM_ABSENT:
+            return SapResultCode::CARD_REMOVED;
+        default:
+            return SapResultCode::GENERIC_FAILURE;
+    }
+}
+
+SapResultCode convertTransferAtrResponseProtoToHal(
+        RIL_SIM_SAP_TRANSFER_ATR_RSP_Response responseProto) {
+    switch(responseProto) {
+        case RIL_SIM_SAP_TRANSFER_ATR_RSP_Response_RIL_E_SUCCESS:
+            return SapResultCode::SUCCESS;
+        case RIL_SIM_SAP_TRANSFER_ATR_RSP_Response_RIL_E_GENERIC_FAILURE:
+            return SapResultCode::GENERIC_FAILURE;
+        case RIL_SIM_SAP_TRANSFER_ATR_RSP_Response_RIL_E_SIM_ALREADY_POWERED_OFF:
+            return SapResultCode::CARD_ALREADY_POWERED_OFF;
+        case RIL_SIM_SAP_TRANSFER_ATR_RSP_Response_RIL_E_SIM_ABSENT:
+            return SapResultCode::CARD_REMOVED;
+        case RIL_SIM_SAP_TRANSFER_ATR_RSP_Response_RIL_E_SIM_DATA_NOT_AVAILABLE:
+            return SapResultCode::DATA_NOT_AVAILABLE;
+        default:
+            return SapResultCode::GENERIC_FAILURE;
+    }
+}
+
+SapResultCode convertPowerResponseProtoToHal(RIL_SIM_SAP_POWER_RSP_Response responseProto) {
+    switch(responseProto) {
+        case RIL_SIM_SAP_POWER_RSP_Response_RIL_E_SUCCESS:
+            return SapResultCode::SUCCESS;
+        case RIL_SIM_SAP_POWER_RSP_Response_RIL_E_GENERIC_FAILURE:
+            return SapResultCode::GENERIC_FAILURE;
+        case RIL_SIM_SAP_POWER_RSP_Response_RIL_E_SIM_ABSENT:
+            return SapResultCode::CARD_REMOVED;
+        case RIL_SIM_SAP_POWER_RSP_Response_RIL_E_SIM_ALREADY_POWERED_OFF:
+            return SapResultCode::CARD_ALREADY_POWERED_OFF;
+        case RIL_SIM_SAP_POWER_RSP_Response_RIL_E_SIM_ALREADY_POWERED_ON:
+            return SapResultCode::CARD_ALREADY_POWERED_ON;
+        default:
+            return SapResultCode::GENERIC_FAILURE;
+    }
+}
+
+SapResultCode convertResetSimResponseProtoToHal(RIL_SIM_SAP_RESET_SIM_RSP_Response responseProto) {
+    switch(responseProto) {
+        case RIL_SIM_SAP_RESET_SIM_RSP_Response_RIL_E_SUCCESS:
+            return SapResultCode::SUCCESS;
+        case RIL_SIM_SAP_RESET_SIM_RSP_Response_RIL_E_GENERIC_FAILURE:
+            return SapResultCode::GENERIC_FAILURE;
+        case RIL_SIM_SAP_RESET_SIM_RSP_Response_RIL_E_SIM_ABSENT:
+            return SapResultCode::CARD_REMOVED;
+        case RIL_SIM_SAP_RESET_SIM_RSP_Response_RIL_E_SIM_NOT_READY:
+            return SapResultCode::CARD_NOT_ACCESSSIBLE;
+        case RIL_SIM_SAP_RESET_SIM_RSP_Response_RIL_E_SIM_ALREADY_POWERED_OFF:
+            return SapResultCode::CARD_ALREADY_POWERED_OFF;
+    }
+    return SapResultCode::GENERIC_FAILURE;
+}
+
+SapResultCode convertTransferCardReaderStatusResponseProtoToHal(
+        RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP_Response responseProto) {
+    switch(responseProto) {
+        case RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP_Response_RIL_E_SUCCESS:
+            return SapResultCode::SUCCESS;
+        case RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP_Response_RIL_E_GENERIC_FAILURE:
+            return SapResultCode::GENERIC_FAILURE;
+        case RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP_Response_RIL_E_SIM_DATA_NOT_AVAILABLE:
+            return SapResultCode::DATA_NOT_AVAILABLE;
+    }
+    return SapResultCode::GENERIC_FAILURE;
+}
+
+void processResponse(MsgHeader *rsp, RilSapSocket *sapSocket, MsgType msgType) {
+    MsgId msgId = rsp->id;
+    uint8_t *data = rsp->payload->bytes;
+    size_t dataLen = rsp->payload->size;
+
+    void *messagePtr = sapDecodeMessage(msgId, msgType, data, dataLen);
+
+    sp<SapImpl> sapImpl = getSapImpl(sapSocket);
+    if (sapImpl->sapCallback == NULL) {
+        RLOGE("processResponse: sapCallback == NULL; msgId = %d; msgType = %d",
+                msgId, msgType);
+        return;
+    }
+
+    RLOGD("processResponse: sapCallback != NULL; msgId = %d; msgType = %d",
+            msgId, msgType);
+
+    Return<void> retStatus;
+    switch (msgId) {
+        case MsgId_RIL_SIM_SAP_CONNECT: {
+            RIL_SIM_SAP_CONNECT_RSP *connectRsp = (RIL_SIM_SAP_CONNECT_RSP *)messagePtr;
+            RLOGD("processResponse: calling sapCallback->connectResponse %d %d %d",
+                    rsp->token,
+                    connectRsp->response,
+                    connectRsp->max_message_size);
+            retStatus = sapImpl->sapCallback->connectResponse(rsp->token,
+                    (SapConnectRsp)connectRsp->response,
+                    connectRsp->max_message_size);
+            break;
+        }
+
+        case MsgId_RIL_SIM_SAP_DISCONNECT:
+            if (msgType == MsgType_RESPONSE) {
+                RLOGD("processResponse: calling sapCallback->disconnectResponse %d", rsp->token);
+                retStatus = sapImpl->sapCallback->disconnectResponse(rsp->token);
+            } else {
+                RIL_SIM_SAP_DISCONNECT_IND *disconnectInd =
+                        (RIL_SIM_SAP_DISCONNECT_IND *)messagePtr;
+                RLOGD("processResponse: calling sapCallback->disconnectIndication %d %d",
+                        rsp->token, disconnectInd->disconnectType);
+                retStatus = sapImpl->sapCallback->disconnectIndication(rsp->token,
+                        (SapDisconnectType)disconnectInd->disconnectType);
+            }
+            break;
+
+        case MsgId_RIL_SIM_SAP_APDU: {
+            RIL_SIM_SAP_APDU_RSP *apduRsp = (RIL_SIM_SAP_APDU_RSP *)messagePtr;
+            SapResultCode apduResponse = convertApduResponseProtoToHal(apduRsp->response);
+            RLOGD("processResponse: calling sapCallback->apduResponse %d %d",
+                    rsp->token, apduResponse);
+            hidl_vec<uint8_t> apduRspVec;
+            if (apduRsp->apduResponse != NULL && apduRsp->apduResponse->size > 0) {
+                apduRspVec.setToExternal(apduRsp->apduResponse->bytes, apduRsp->apduResponse->size);
+            }
+            retStatus = sapImpl->sapCallback->apduResponse(rsp->token, apduResponse, apduRspVec);
+            break;
+        }
+
+        case MsgId_RIL_SIM_SAP_TRANSFER_ATR: {
+            RIL_SIM_SAP_TRANSFER_ATR_RSP *transferAtrRsp =
+                (RIL_SIM_SAP_TRANSFER_ATR_RSP *)messagePtr;
+            SapResultCode transferAtrResponse =
+                convertTransferAtrResponseProtoToHal(transferAtrRsp->response);
+            RLOGD("processResponse: calling sapCallback->transferAtrResponse %d %d",
+                    rsp->token, transferAtrResponse);
+            hidl_vec<uint8_t> transferAtrRspVec;
+            if (transferAtrRsp->atr != NULL && transferAtrRsp->atr->size > 0) {
+                transferAtrRspVec.setToExternal(transferAtrRsp->atr->bytes,
+                        transferAtrRsp->atr->size);
+            }
+            retStatus = sapImpl->sapCallback->transferAtrResponse(rsp->token, transferAtrResponse,
+                    transferAtrRspVec);
+            break;
+        }
+
+        case MsgId_RIL_SIM_SAP_POWER: {
+            SapResultCode powerResponse = convertPowerResponseProtoToHal(
+                    ((RIL_SIM_SAP_POWER_RSP *)messagePtr)->response);
+            RLOGD("processResponse: calling sapCallback->powerResponse %d %d",
+                    rsp->token, powerResponse);
+            retStatus = sapImpl->sapCallback->powerResponse(rsp->token, powerResponse);
+            break;
+        }
+
+        case MsgId_RIL_SIM_SAP_RESET_SIM: {
+            SapResultCode resetSimResponse = convertResetSimResponseProtoToHal(
+                    ((RIL_SIM_SAP_RESET_SIM_RSP *)messagePtr)->response);
+            RLOGD("processResponse: calling sapCallback->resetSimResponse %d %d",
+                    rsp->token, resetSimResponse);
+            retStatus = sapImpl->sapCallback->resetSimResponse(rsp->token, resetSimResponse);
+            break;
+        }
+
+        case MsgId_RIL_SIM_SAP_STATUS: {
+            RIL_SIM_SAP_STATUS_IND *statusInd = (RIL_SIM_SAP_STATUS_IND *)messagePtr;
+            RLOGD("processResponse: calling sapCallback->statusIndication %d %d",
+                    rsp->token, statusInd->statusChange);
+            retStatus = sapImpl->sapCallback->statusIndication(rsp->token,
+                    (SapStatus)statusInd->statusChange);
+            break;
+        }
+
+        case MsgId_RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS: {
+            RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP *transferStatusRsp =
+                    (RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP *)messagePtr;
+            SapResultCode transferCardReaderStatusResponse =
+                    convertTransferCardReaderStatusResponseProtoToHal(
+                    transferStatusRsp->response);
+            RLOGD("processResponse: calling sapCallback->transferCardReaderStatusResponse %d %d %d",
+                    rsp->token,
+                    transferCardReaderStatusResponse,
+                    transferStatusRsp->CardReaderStatus);
+            retStatus = sapImpl->sapCallback->transferCardReaderStatusResponse(rsp->token,
+                    transferCardReaderStatusResponse,
+                    transferStatusRsp->CardReaderStatus);
+            break;
+        }
+
+        case MsgId_RIL_SIM_SAP_ERROR_RESP: {
+            RLOGD("processResponse: calling sapCallback->errorResponse %d", rsp->token);
+            retStatus = sapImpl->sapCallback->errorResponse(rsp->token);
+            break;
+        }
+
+        case MsgId_RIL_SIM_SAP_SET_TRANSFER_PROTOCOL: {
+            SapResultCode setTransferProtocolResponse;
+            if (((RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP *)messagePtr)->response ==
+                    RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP_Response_RIL_E_SUCCESS) {
+                setTransferProtocolResponse = SapResultCode::SUCCESS;
+            } else {
+                setTransferProtocolResponse = SapResultCode::NOT_SUPPORTED;
+            }
+            RLOGD("processResponse: calling sapCallback->transferProtocolResponse %d %d",
+                    rsp->token, setTransferProtocolResponse);
+            retStatus = sapImpl->sapCallback->transferProtocolResponse(rsp->token,
+                    setTransferProtocolResponse);
+            break;
+        }
+
+        default:
+            return;
+    }
+    sapImpl->checkReturnStatus(retStatus);
+}
+
+void sap::processResponse(MsgHeader *rsp, RilSapSocket *sapSocket) {
+    processResponse(rsp, sapSocket, MsgType_RESPONSE);
+}
+
+void sap::processUnsolResponse(MsgHeader *rsp, RilSapSocket *sapSocket) {
+    processResponse(rsp, sapSocket, MsgType_UNSOL_RESPONSE);
+}
+
+void sap::registerService(RIL_RadioFunctions *callbacks) {
+    using namespace android::hardware;
+    int simCount = 1;
+    const char *serviceNames[] = {
+        android::RIL_getServiceName()
+        #if (SIM_COUNT >= 2)
+        , RIL2_SERVICE_NAME
+        #if (SIM_COUNT >= 3)
+        , RIL3_SERVICE_NAME
+        #if (SIM_COUNT >= 4)
+        , RIL4_SERVICE_NAME
+        #endif
+        #endif
+        #endif
+    };
+
+    RIL_SOCKET_ID socketIds[] = {
+        RIL_SOCKET_1
+        #if (SIM_COUNT >= 2)
+        , RIL_SOCKET_2
+        #if (SIM_COUNT >= 3)
+        , RIL_SOCKET_3
+        #if (SIM_COUNT >= 4)
+        , RIL_SOCKET_4
+        #endif
+        #endif
+        #endif
+    };
+    #if (SIM_COUNT >= 2)
+    simCount = SIM_COUNT;
+    #endif
+
+    for (int i = 0; i < simCount; i++) {
+        sapService[i] = new SapImpl;
+        sapService[i]->slotId = i;
+        sapService[i]->rilSocketId = socketIds[i];
+        RLOGD("registerService: starting ISap %s for slotId %d", serviceNames[i], i);
+        android::status_t status = sapService[i]->registerAsService(serviceNames[i]);
+        RLOGD("registerService: started ISap %s status %d", serviceNames[i], status);
+    }
+}