Home | History | Annotate | Download | only in sap
      1 package com.android.bluetooth.sap;
      2 
      3 import java.io.IOException;
      4 import java.io.InputStream;
      5 import java.util.ArrayList;
      6 import java.util.List;
      7 import java.util.concurrent.atomic.AtomicLong;
      8 
      9 import org.android.btsap.SapApi.MsgHeader;
     10 
     11 import com.google.protobuf.micro.CodedInputStreamMicro;
     12 import com.google.protobuf.micro.CodedOutputStreamMicro;
     13 
     14 import android.hardware.radio.V1_0.ISap;
     15 import android.hardware.radio.V1_0.ISapCallback;
     16 
     17 import android.net.LocalSocket;
     18 import android.net.LocalSocketAddress;
     19 import android.os.Handler;
     20 import android.os.HwBinder;
     21 import android.os.Message;
     22 import android.os.RemoteException;
     23 import android.util.Log;
     24 
     25 public class SapRilReceiver {
     26     private static final String TAG = "SapRilReceiver";
     27     public static final boolean DEBUG = true;
     28     public static final boolean VERBOSE = true;
     29 
     30     private static final String SERVICE_NAME_RIL_BT = "slot1";
     31     // match with constant in ril.cpp - as in RIL.java
     32     private static final int SOCKET_OPEN_RETRY_MILLIS = 4 * 1000;
     33 
     34     SapCallback mSapCallback;
     35     volatile ISap mSapProxy = null;
     36     Object mSapProxyLock = new Object();
     37     final AtomicLong mSapProxyCookie = new AtomicLong(0);
     38     final SapProxyDeathRecipient mSapProxyDeathRecipient;
     39 
     40     private Handler mSapServerMsgHandler = null;
     41     private Handler mSapServiceHandler = null;
     42 
     43     public static final int RIL_MAX_COMMAND_BYTES = (8 * 1024);
     44     byte[] buffer = new byte[RIL_MAX_COMMAND_BYTES];
     45 
     46     final class SapProxyDeathRecipient implements HwBinder.DeathRecipient {
     47         @Override
     48         public void serviceDied(long cookie) {
     49             // Deal with service going away
     50             Log.d(TAG, "serviceDied");
     51             // todo: temp hack to send delayed message so that rild is back up by then
     52             // mSapHandler.sendMessage(mSapHandler.obtainMessage(EVENT_SAP_PROXY_DEAD, cookie));
     53             mSapServerMsgHandler.sendMessageDelayed(
     54                     mSapServerMsgHandler.obtainMessage(SapServer.SAP_PROXY_DEAD, cookie),
     55                     SapServer.ISAP_GET_SERVICE_DELAY_MILLIS);
     56         }
     57     }
     58 
     59     private void sendSapMessage(SapMessage sapMessage) {
     60         if (sapMessage.getMsgType() < SapMessage.ID_RIL_BASE) {
     61             sendClientMessage(sapMessage);
     62         } else {
     63             sendRilIndMessage(sapMessage);
     64         }
     65     }
     66 
     67     private void removeOngoingReqAndSendMessage(int token, SapMessage sapMessage) {
     68         Integer reqType = SapMessage.sOngoingRequests.remove(token);
     69         if (VERBOSE) {
     70             Log.d(TAG, "removeOngoingReqAndSendMessage: token " + token + " reqType "
     71                             + (reqType == null ? "null" : SapMessage.getMsgTypeName(reqType)));
     72         }
     73         sendSapMessage(sapMessage);
     74     }
     75 
     76     class SapCallback extends ISapCallback.Stub {
     77         public void connectResponse(int token, int sapConnectRsp, int maxMsgSize) {
     78             Log.d(TAG, "connectResponse: token " + token + " sapConnectRsp " + sapConnectRsp
     79                             + " maxMsgSize " + maxMsgSize);
     80             SapService.notifyUpdateWakeLock(mSapServiceHandler);
     81             SapMessage sapMessage = new SapMessage(SapMessage.ID_CONNECT_RESP);
     82             sapMessage.setConnectionStatus(sapConnectRsp);
     83             if (sapConnectRsp == SapMessage.CON_STATUS_ERROR_MAX_MSG_SIZE_UNSUPPORTED) {
     84                 sapMessage.setMaxMsgSize(maxMsgSize);
     85             }
     86             sapMessage.setResultCode(SapMessage.INVALID_VALUE);
     87             removeOngoingReqAndSendMessage(token, sapMessage);
     88         }
     89 
     90         public void disconnectResponse(int token) {
     91             Log.d(TAG, "disconnectResponse: token " + token);
     92             SapService.notifyUpdateWakeLock(mSapServiceHandler);
     93             SapMessage sapMessage = new SapMessage(SapMessage.ID_DISCONNECT_RESP);
     94             sapMessage.setResultCode(SapMessage.INVALID_VALUE);
     95             removeOngoingReqAndSendMessage(token, sapMessage);
     96         }
     97 
     98         public void disconnectIndication(int token, int disconnectType) {
     99             Log.d(TAG,
    100                     "disconnectIndication: token " + token + " disconnectType " + disconnectType);
    101             SapService.notifyUpdateWakeLock(mSapServiceHandler);
    102             SapMessage sapMessage = new SapMessage(SapMessage.ID_RIL_UNSOL_DISCONNECT_IND);
    103             sapMessage.setDisconnectionType(disconnectType);
    104             sendSapMessage(sapMessage);
    105         }
    106 
    107         public void apduResponse(int token, int resultCode, ArrayList<Byte> apduRsp) {
    108             Log.d(TAG, "apduResponse: token " + token);
    109             SapService.notifyUpdateWakeLock(mSapServiceHandler);
    110             SapMessage sapMessage = new SapMessage(SapMessage.ID_TRANSFER_APDU_RESP);
    111             sapMessage.setResultCode(resultCode);
    112             if (resultCode == SapMessage.RESULT_OK) {
    113                 sapMessage.setApduResp(arrayListToPrimitiveArray(apduRsp));
    114             }
    115             removeOngoingReqAndSendMessage(token, sapMessage);
    116         }
    117 
    118         public void transferAtrResponse(int token, int resultCode, ArrayList<Byte> atr) {
    119             Log.d(TAG, "transferAtrResponse: token " + token + " resultCode " + resultCode);
    120             SapService.notifyUpdateWakeLock(mSapServiceHandler);
    121             SapMessage sapMessage = new SapMessage(SapMessage.ID_TRANSFER_ATR_RESP);
    122             sapMessage.setResultCode(resultCode);
    123             if (resultCode == SapMessage.RESULT_OK) {
    124                 sapMessage.setAtr(arrayListToPrimitiveArray(atr));
    125             }
    126             removeOngoingReqAndSendMessage(token, sapMessage);
    127         }
    128 
    129         public void powerResponse(int token, int resultCode) {
    130             Log.d(TAG, "powerResponse: token " + token + " resultCode " + resultCode);
    131             SapService.notifyUpdateWakeLock(mSapServiceHandler);
    132             Integer reqType = SapMessage.sOngoingRequests.remove(token);
    133             if (VERBOSE) {
    134                 Log.d(TAG, "powerResponse: reqType "
    135                                 + (reqType == null ? "null" : SapMessage.getMsgTypeName(reqType)));
    136             }
    137             SapMessage sapMessage;
    138             if (reqType == SapMessage.ID_POWER_SIM_OFF_REQ) {
    139                 sapMessage = new SapMessage(SapMessage.ID_POWER_SIM_OFF_RESP);
    140             } else if (reqType == SapMessage.ID_POWER_SIM_ON_REQ) {
    141                 sapMessage = new SapMessage(SapMessage.ID_POWER_SIM_ON_RESP);
    142             } else {
    143                 return;
    144             }
    145             sapMessage.setResultCode(resultCode);
    146             sendSapMessage(sapMessage);
    147         }
    148 
    149         public void resetSimResponse(int token, int resultCode) {
    150             Log.d(TAG, "resetSimResponse: token " + token + " resultCode " + resultCode);
    151             SapService.notifyUpdateWakeLock(mSapServiceHandler);
    152             SapMessage sapMessage = new SapMessage(SapMessage.ID_RESET_SIM_RESP);
    153             sapMessage.setResultCode(resultCode);
    154             removeOngoingReqAndSendMessage(token, sapMessage);
    155         }
    156 
    157         public void statusIndication(int token, int status) {
    158             Log.d(TAG, "statusIndication: token " + token + " status " + status);
    159             SapService.notifyUpdateWakeLock(mSapServiceHandler);
    160             SapMessage sapMessage = new SapMessage(SapMessage.ID_STATUS_IND);
    161             sapMessage.setStatusChange(status);
    162             sendSapMessage(sapMessage);
    163         }
    164 
    165         public void transferCardReaderStatusResponse(
    166                 int token, int resultCode, int cardReaderStatus) {
    167             Log.d(TAG, "transferCardReaderStatusResponse: token " + token + " resultCode "
    168                             + resultCode + " cardReaderStatus " + cardReaderStatus);
    169             SapService.notifyUpdateWakeLock(mSapServiceHandler);
    170             SapMessage sapMessage = new SapMessage(SapMessage.ID_TRANSFER_CARD_READER_STATUS_RESP);
    171             sapMessage.setResultCode(resultCode);
    172             if (resultCode == SapMessage.RESULT_OK) {
    173                 sapMessage.setCardReaderStatus(cardReaderStatus);
    174             }
    175             removeOngoingReqAndSendMessage(token, sapMessage);
    176         }
    177 
    178         public void errorResponse(int token) {
    179             Log.d(TAG, "errorResponse: token " + token);
    180             SapService.notifyUpdateWakeLock(mSapServiceHandler);
    181             // Since ERROR_RESP isn't supported by createUnsolicited(), keeping behavior same here
    182             // SapMessage sapMessage = new SapMessage(SapMessage.ID_ERROR_RESP);
    183             SapMessage sapMessage = new SapMessage(SapMessage.ID_RIL_UNKNOWN);
    184             sendSapMessage(sapMessage);
    185         }
    186 
    187         public void transferProtocolResponse(int token, int resultCode) {
    188             Log.d(TAG, "transferProtocolResponse: token " + token + " resultCode " + resultCode);
    189             SapService.notifyUpdateWakeLock(mSapServiceHandler);
    190             SapMessage sapMessage = new SapMessage(SapMessage.ID_SET_TRANSPORT_PROTOCOL_RESP);
    191             sapMessage.setResultCode(resultCode);
    192             removeOngoingReqAndSendMessage(token, sapMessage);
    193         }
    194     }
    195 
    196     public static byte[] arrayListToPrimitiveArray(List<Byte> bytes) {
    197         byte[] ret = new byte[bytes.size()];
    198         for (int i = 0; i < ret.length; i++) {
    199             ret[i] = bytes.get(i);
    200         }
    201         return ret;
    202     }
    203 
    204     public Object getSapProxyLock() {
    205         return mSapProxyLock;
    206     }
    207 
    208     public ISap getSapProxy() {
    209         synchronized (mSapProxyLock) {
    210             if (mSapProxy != null) {
    211                 return mSapProxy;
    212             }
    213 
    214             try {
    215                 mSapProxy = ISap.getService(SERVICE_NAME_RIL_BT);
    216                 if (mSapProxy != null) {
    217                     mSapProxy.linkToDeath(
    218                             mSapProxyDeathRecipient, mSapProxyCookie.incrementAndGet());
    219                     mSapProxy.setCallback(mSapCallback);
    220                 } else {
    221                     Log.e(TAG, "getSapProxy: mSapProxy == null");
    222                 }
    223             } catch (RemoteException | RuntimeException e) {
    224                 mSapProxy = null;
    225                 Log.e(TAG, "getSapProxy: exception: " + e);
    226             }
    227 
    228             if (mSapProxy == null) {
    229                 // if service is not up, treat it like death notification to try to get service
    230                 // again
    231                 mSapServerMsgHandler.sendMessageDelayed(
    232                         mSapServerMsgHandler.obtainMessage(
    233                                 SapServer.SAP_PROXY_DEAD, mSapProxyCookie.get()),
    234                         SapServer.ISAP_GET_SERVICE_DELAY_MILLIS);
    235             }
    236             return mSapProxy;
    237         }
    238     }
    239 
    240     public void resetSapProxy() {
    241         synchronized (mSapProxyLock) {
    242             mSapProxy = null;
    243         }
    244     }
    245 
    246     public SapRilReceiver(Handler SapServerMsgHandler, Handler sapServiceHandler) {
    247         mSapServerMsgHandler = SapServerMsgHandler;
    248         mSapServiceHandler = sapServiceHandler;
    249         mSapCallback = new SapCallback();
    250         mSapProxyDeathRecipient = new SapProxyDeathRecipient();
    251         synchronized (mSapProxyLock) {
    252             mSapProxy = getSapProxy();
    253         }
    254     }
    255 
    256     /**
    257      * Notify SapServer that this class is ready for shutdown.
    258      */
    259     void notifyShutdown() {
    260         if (DEBUG) Log.i(TAG, "notifyShutdown()");
    261         // If we are already shutdown, don't bother sending a notification.
    262         synchronized (mSapProxyLock) {
    263             if (mSapProxy != null) sendShutdownMessage();
    264         }
    265     }
    266 
    267     /**
    268      * Read the message into buffer
    269      * @param is
    270      * @param buffer
    271      * @return the length of the message
    272      * @throws IOException
    273      */
    274     private static int readMessage(InputStream is, byte[] buffer) throws IOException {
    275         int countRead;
    276         int offset;
    277         int remaining;
    278         int messageLength;
    279 
    280         // Read in the length of the message
    281         offset = 0;
    282         remaining = 4;
    283         do {
    284             countRead = is.read(buffer, offset, remaining);
    285 
    286             if (countRead < 0 ) {
    287                 Log.e(TAG, "Hit EOS reading message length");
    288                 return -1;
    289             }
    290 
    291             offset += countRead;
    292             remaining -= countRead;
    293         } while (remaining > 0);
    294 
    295         messageLength = ((buffer[0] & 0xff) << 24)
    296                 | ((buffer[1] & 0xff) << 16)
    297                 | ((buffer[2] & 0xff) << 8)
    298                 | (buffer[3] & 0xff);
    299         if (VERBOSE) Log.e(TAG,"Message length found to be: "+messageLength);
    300         // Read the message
    301         offset = 0;
    302         remaining = messageLength;
    303         do {
    304             countRead = is.read(buffer, offset, remaining);
    305 
    306             if (countRead < 0 ) {
    307                 Log.e(TAG, "Hit EOS reading message.  messageLength=" + messageLength
    308                         + " remaining=" + remaining);
    309                 return -1;
    310             }
    311 
    312             offset += countRead;
    313             remaining -= countRead;
    314         } while (remaining > 0);
    315 
    316         return messageLength;
    317     }
    318 
    319     /**
    320      * Notify SapServer that the RIL socket is connected
    321      */
    322     void sendRilConnectMessage() {
    323         if (mSapServerMsgHandler != null) {
    324             mSapServerMsgHandler.sendEmptyMessage(SapServer.SAP_MSG_RIL_CONNECT);
    325         }
    326     }
    327 
    328     /**
    329      * Send reply (solicited) message from the RIL to the Sap Server Handler Thread
    330      * @param sapMsg The message to send
    331      */
    332     private void sendClientMessage(SapMessage sapMsg) {
    333         Message newMsg = mSapServerMsgHandler.obtainMessage(SapServer.SAP_MSG_RFC_REPLY, sapMsg);
    334         mSapServerMsgHandler.sendMessage(newMsg);
    335     }
    336 
    337     /**
    338      * Send a shutdown signal to SapServer to indicate the
    339      */
    340     private void sendShutdownMessage() {
    341         if (mSapServerMsgHandler != null) {
    342             mSapServerMsgHandler.sendEmptyMessage(SapServer.SAP_RIL_SOCK_CLOSED);
    343         }
    344     }
    345 
    346     /**
    347      * Send indication (unsolicited) message from RIL to the Sap Server Handler Thread
    348      * @param sapMsg The message to send
    349      */
    350     private void sendRilIndMessage(SapMessage sapMsg) {
    351         Message newMsg = mSapServerMsgHandler.obtainMessage(SapServer.SAP_MSG_RIL_IND, sapMsg);
    352         mSapServerMsgHandler.sendMessage(newMsg);
    353     }
    354 
    355 }
    356