1package com.android.bluetooth.sap; 2 3import java.io.IOException; 4import java.io.InputStream; 5import java.util.ArrayList; 6import java.util.List; 7import java.util.concurrent.atomic.AtomicLong; 8 9import org.android.btsap.SapApi.MsgHeader; 10 11import com.google.protobuf.micro.CodedInputStreamMicro; 12import com.google.protobuf.micro.CodedOutputStreamMicro; 13 14import android.hardware.radio.V1_0.ISap; 15import android.hardware.radio.V1_0.ISapCallback; 16 17import android.net.LocalSocket; 18import android.net.LocalSocketAddress; 19import android.os.Handler; 20import android.os.HwBinder; 21import android.os.Message; 22import android.os.RemoteException; 23import android.util.Log; 24 25public 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