Merge "Remove SAP socket"
diff --git a/src/com/android/bluetooth/sap/SapRilReceiver.java b/src/com/android/bluetooth/sap/SapRilReceiver.java
index d796fb6..028252c 100644
--- a/src/com/android/bluetooth/sap/SapRilReceiver.java
+++ b/src/com/android/bluetooth/sap/SapRilReceiver.java
@@ -22,8 +22,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-public class SapRilReceiver implements Runnable {
-
+public class SapRilReceiver {
     private static final String TAG = "SapRilReceiver";
     public static final boolean DEBUG = true;
     public static final boolean VERBOSE = true;
@@ -32,12 +31,9 @@
     // match with constant in ril.cpp - as in RIL.java
     private static final int SOCKET_OPEN_RETRY_MILLIS = 4 * 1000;
 
-    LocalSocket mSocket = null;
-    CodedOutputStreamMicro mRilBtOutStream = null;
-    InputStream mRilBtInStream = null;
-
     SapCallback mSapCallback;
     volatile ISap mSapProxy = null;
+    Object mSapProxyLock = new Object();
     final AtomicLong mSapProxyCookie = new AtomicLong(0);
     final SapProxyDeathRecipient mSapProxyDeathRecipient;
 
@@ -81,6 +77,7 @@
         public void connectResponse(int token, int sapConnectRsp, int maxMsgSize) {
             Log.d(TAG, "connectResponse: token " + token + " sapConnectRsp " + sapConnectRsp
                             + " maxMsgSize " + maxMsgSize);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             SapMessage sapMessage = new SapMessage(SapMessage.ID_CONNECT_RESP);
             sapMessage.setConnectionStatus(sapConnectRsp);
             if (sapConnectRsp == SapMessage.CON_STATUS_ERROR_MAX_MSG_SIZE_UNSUPPORTED) {
@@ -92,6 +89,7 @@
 
         public void disconnectResponse(int token) {
             Log.d(TAG, "disconnectResponse: token " + token);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             SapMessage sapMessage = new SapMessage(SapMessage.ID_DISCONNECT_RESP);
             sapMessage.setResultCode(SapMessage.INVALID_VALUE);
             removeOngoingReqAndSendMessage(token, sapMessage);
@@ -100,6 +98,7 @@
         public void disconnectIndication(int token, int disconnectType) {
             Log.d(TAG,
                     "disconnectIndication: token " + token + " disconnectType " + disconnectType);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             SapMessage sapMessage = new SapMessage(SapMessage.ID_RIL_UNSOL_DISCONNECT_IND);
             sapMessage.setDisconnectionType(disconnectType);
             sendSapMessage(sapMessage);
@@ -107,6 +106,7 @@
 
         public void apduResponse(int token, int resultCode, ArrayList<Byte> apduRsp) {
             Log.d(TAG, "apduResponse: token " + token);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             SapMessage sapMessage = new SapMessage(SapMessage.ID_TRANSFER_APDU_RESP);
             sapMessage.setResultCode(resultCode);
             if (resultCode == SapMessage.RESULT_OK) {
@@ -117,6 +117,7 @@
 
         public void transferAtrResponse(int token, int resultCode, ArrayList<Byte> atr) {
             Log.d(TAG, "transferAtrResponse: token " + token + " resultCode " + resultCode);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             SapMessage sapMessage = new SapMessage(SapMessage.ID_TRANSFER_ATR_RESP);
             sapMessage.setResultCode(resultCode);
             if (resultCode == SapMessage.RESULT_OK) {
@@ -127,6 +128,7 @@
 
         public void powerResponse(int token, int resultCode) {
             Log.d(TAG, "powerResponse: token " + token + " resultCode " + resultCode);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             Integer reqType = SapMessage.sOngoingRequests.remove(token);
             if (VERBOSE) {
                 Log.d(TAG, "powerResponse: reqType "
@@ -146,6 +148,7 @@
 
         public void resetSimResponse(int token, int resultCode) {
             Log.d(TAG, "resetSimResponse: token " + token + " resultCode " + resultCode);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             SapMessage sapMessage = new SapMessage(SapMessage.ID_RESET_SIM_RESP);
             sapMessage.setResultCode(resultCode);
             removeOngoingReqAndSendMessage(token, sapMessage);
@@ -153,6 +156,7 @@
 
         public void statusIndication(int token, int status) {
             Log.d(TAG, "statusIndication: token " + token + " status " + status);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             SapMessage sapMessage = new SapMessage(SapMessage.ID_STATUS_IND);
             sapMessage.setStatusChange(status);
             sendSapMessage(sapMessage);
@@ -162,6 +166,7 @@
                 int token, int resultCode, int cardReaderStatus) {
             Log.d(TAG, "transferCardReaderStatusResponse: token " + token + " resultCode "
                             + resultCode + " cardReaderStatus " + cardReaderStatus);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             SapMessage sapMessage = new SapMessage(SapMessage.ID_TRANSFER_CARD_READER_STATUS_RESP);
             sapMessage.setResultCode(resultCode);
             if (resultCode == SapMessage.RESULT_OK) {
@@ -172,6 +177,7 @@
 
         public void errorResponse(int token) {
             Log.d(TAG, "errorResponse: token " + token);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             // Since ERROR_RESP isn't supported by createUnsolicited(), keeping behavior same here
             // SapMessage sapMessage = new SapMessage(SapMessage.ID_ERROR_RESP);
             SapMessage sapMessage = new SapMessage(SapMessage.ID_RIL_UNKNOWN);
@@ -180,6 +186,7 @@
 
         public void transferProtocolResponse(int token, int resultCode) {
             Log.d(TAG, "transferProtocolResponse: token " + token + " resultCode " + resultCode);
+            SapService.notifyUpdateWakeLock(mSapServiceHandler);
             SapMessage sapMessage = new SapMessage(SapMessage.ID_SET_TRANSPORT_PROTOCOL_RESP);
             sapMessage.setResultCode(resultCode);
             removeOngoingReqAndSendMessage(token, sapMessage);
@@ -194,36 +201,46 @@
         return ret;
     }
 
+    public Object getSapProxyLock() {
+        return mSapProxyLock;
+    }
+
     public ISap getSapProxy() {
-        if (mSapProxy != null) {
+        synchronized (mSapProxyLock) {
+            if (mSapProxy != null) {
+                return mSapProxy;
+            }
+
+            try {
+                mSapProxy = ISap.getService(SOCKET_NAME_RIL_BT);
+                if (mSapProxy != null) {
+                    mSapProxy.linkToDeath(
+                            mSapProxyDeathRecipient, mSapProxyCookie.incrementAndGet());
+                    mSapProxy.setCallback(mSapCallback);
+                } else {
+                    Log.e(TAG, "getSapProxy: mSapProxy == null");
+                }
+            } catch (RemoteException | RuntimeException e) {
+                mSapProxy = null;
+                Log.e(TAG, "getSapProxy: exception: " + e);
+            }
+
+            if (mSapProxy == null) {
+                // if service is not up, treat it like death notification to try to get service
+                // again
+                mSapServerMsgHandler.sendMessageDelayed(
+                        mSapServerMsgHandler.obtainMessage(
+                                SapServer.SAP_PROXY_DEAD, mSapProxyCookie.get()),
+                        SapServer.ISAP_GET_SERVICE_DELAY_MILLIS);
+            }
             return mSapProxy;
         }
-
-        try {
-            mSapProxy = ISap.getService(SOCKET_NAME_RIL_BT);
-            if (mSapProxy != null) {
-                Log.d(TAG, "getSapProxy: mSapProxy != null; calling setCallback()");
-                mSapProxy.linkToDeath(mSapProxyDeathRecipient, mSapProxyCookie.incrementAndGet());
-                mSapProxy.setCallback(mSapCallback);
-            } else {
-                Log.e(TAG, "getSapProxy: mSapProxy == null");
-            }
-        } catch (RemoteException | RuntimeException e) {
-            mSapProxy = null;
-
-            // if service is not up, treat it like death notification to try to get service again
-            mSapServerMsgHandler.sendMessageDelayed(
-                    mSapServerMsgHandler.obtainMessage(
-                            SapServer.SAP_PROXY_DEAD, mSapProxyCookie.get()),
-                    SapServer.ISAP_GET_SERVICE_DELAY_MILLIS);
-
-            Log.e(TAG, "getSapProxy: exception", e);
-        }
-        return mSapProxy;
     }
 
     public void resetSapProxy() {
-        mSapProxy = null;
+        synchronized (mSapProxyLock) {
+            mSapProxy = null;
+        }
     }
 
     public SapRilReceiver(Handler SapServerMsgHandler, Handler sapServiceHandler) {
@@ -231,106 +248,19 @@
         mSapServiceHandler = sapServiceHandler;
         mSapCallback = new SapCallback();
         mSapProxyDeathRecipient = new SapProxyDeathRecipient();
-        mSapProxy = getSapProxy();
-    }
-
-    /**
-     * Open the RIL-BT socket in rild. Will continuously try to open the BT socket until
-     * success. (Based on the approach used to open the rild socket in telephony)
-     * @return The socket handle
-     */
-    public static LocalSocket openRilBtSocket() {
-        int retryCount = 0;
-        LocalSocket rilSocket = null;
-
-        for (;;) {
-            LocalSocketAddress address;
-
-            try {
-                rilSocket = new LocalSocket();
-                address = new LocalSocketAddress(SOCKET_NAME_RIL_BT,
-                        LocalSocketAddress.Namespace.RESERVED);
-                rilSocket.connect(address);
-                break; // Socket opened
-            } catch (IOException ex){
-                try {
-                    if (rilSocket != null) {
-                        rilSocket.close();
-                    }
-                } catch (IOException ex2) {
-                    //ignore failure to close after failure to connect
-                }
-
-                // don't print an error message after the the first time
-                // or after the 8th time
-                if (retryCount == 8) {
-                    Log.e (TAG,
-                        "Couldn't find '" + SOCKET_NAME_RIL_BT
-                        + "' socket after " + retryCount
-                        + " times, continuing to retry silently");
-                } else if (retryCount > 0 && retryCount < 8) {
-                    Log.i (TAG,
-                        "Couldn't find '" + SOCKET_NAME_RIL_BT
-                        + "' socket; retrying after timeout");
-                    if (VERBOSE) Log.w(TAG, ex);
-                }
-
-                try {
-                    Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
-                } catch (InterruptedException er) {
-                }
-
-                retryCount++;
-                continue;
-            }
+        synchronized (mSapProxyLock) {
+            mSapProxy = getSapProxy();
         }
-        return rilSocket;
-    }
-
-
-    public CodedOutputStreamMicro getRilBtOutStream() {
-        return mRilBtOutStream;
     }
 
     /**
      * Notify SapServer that this class is ready for shutdown.
      */
-    private void notifyShutdown() {
+    void notifyShutdown() {
         if (DEBUG) Log.i(TAG, "notifyShutdown()");
         // If we are already shutdown, don't bother sending a notification.
-        synchronized (this) {
-            if (mSocket != null) sendShutdownMessage();
-        }
-    }
-
-    /**
-     * This will terminate the SapRilReceiver thread, by closing the RIL-BT in-/output
-     * streams.
-     */
-    public void shutdown() {
-        if (DEBUG) Log.i(TAG, "shutdown()");
-
-        /* On Android you need to close the IOstreams using Socket.shutdown*
-         * The IOstream close must not be used, as it some how decouples the
-         * stream from the socket, and when the socket is closed, the pending
-         * reads never return nor throw and exception.
-         * Hence here we use the shutdown method: */
-        synchronized (this) {
-            if (mSocket != null) {
-                try {
-                    mSocket.shutdownOutput();
-                } catch (IOException e) {}
-                try {
-                    mSocket.shutdownInput();
-                } catch (IOException e) {}
-                try {
-                    mSocket.close();
-                } catch (IOException ex) {
-                    if (VERBOSE) Log.e(TAG,"Uncaught exception", ex);
-                } finally {
-                    mSocket = null;
-                }
-            }
+        synchronized (mSapProxyLock) {
+            if (mSapProxy != null) sendShutdownMessage();
         }
     }
 
@@ -387,69 +317,9 @@
     }
 
     /**
-     * The RIL reader thread. Will handle open of the RIL-BT socket, and notify
-     * SapServer when done.
-     */
-    @Override
-    public void run() {
-
-        try {
-            if (VERBOSE) Log.i(TAG, "Starting RilBtReceiverThread...");
-
-            mSocket = openRilBtSocket();
-            mRilBtInStream = mSocket.getInputStream();
-            mRilBtOutStream = CodedOutputStreamMicro.newInstance(mSocket.getOutputStream());
-
-            // Notify the SapServer that we have connected to the RilBtSocket
-            sendRilConnectMessage();
-
-            // The main loop - read messages and forward to SAP server
-            for (;;) {
-                SapMessage sapMsg = null;
-                MsgHeader rilMsg;
-
-                if (VERBOSE) Log.i(TAG, "Waiting for incoming message...");
-                int length = readMessage(mRilBtInStream, buffer);
-
-                SapService.notifyUpdateWakeLock(mSapServiceHandler);
-
-                if (length == -1) {
-                    if (DEBUG) Log.i(TAG, "EOF reached - closing down.");
-                    break;
-                }
-
-                CodedInputStreamMicro msgStream =
-                        CodedInputStreamMicro.newInstance(buffer, 0, length);
-
-                rilMsg = MsgHeader.parseFrom(msgStream);
-
-                if (VERBOSE) Log.i(TAG, "Message received.");
-
-                sapMsg = SapMessage.newInstance(rilMsg);
-
-                if (sapMsg != null && sapMsg.getMsgType() != SapMessage.INVALID_VALUE)
-                {
-                    if (sapMsg.getMsgType() < SapMessage.ID_RIL_BASE) {
-                        sendClientMessage(sapMsg);
-                    } else {
-                        sendRilIndMessage(sapMsg);
-                    }
-                } // else simply ignore it
-            }
-
-        } catch (IOException e) {
-            notifyShutdown(); /* Only needed in case of a connection error */
-            Log.i(TAG, "'" + SOCKET_NAME_RIL_BT + "' socket inputStream closed", e);
-
-        } finally {
-            Log.i(TAG, "Disconnected from '" + SOCKET_NAME_RIL_BT + "' socket");
-        }
-    }
-
-    /**
      * Notify SapServer that the RIL socket is connected
      */
-    private void sendRilConnectMessage() {
+    void sendRilConnectMessage() {
         if (mSapServerMsgHandler != null) {
             mSapServerMsgHandler.sendEmptyMessage(SapServer.SAP_MSG_RIL_CONNECT);
         }
diff --git a/src/com/android/bluetooth/sap/SapServer.java b/src/com/android/bluetooth/sap/SapServer.java
index 527833f..5030970 100644
--- a/src/com/android/bluetooth/sap/SapServer.java
+++ b/src/com/android/bluetooth/sap/SapServer.java
@@ -61,7 +61,6 @@
     private BufferedInputStream mRfcommIn = null;
     /* References to the SapRilReceiver object */
     private SapRilReceiver mRilBtReceiver = null;
-    private Thread mRilBtReceiverThread = null;
     /* The message handler members */
     private Handler mSapHandler = null;
     private HandlerThread mHandlerThread = null;
@@ -309,7 +308,6 @@
             mSapHandler = new Handler(sapLooper, this);
 
             mRilBtReceiver = new SapRilReceiver(mSapHandler, mSapServiceHandler);
-            mRilBtReceiverThread = new Thread(mRilBtReceiver, "RilBtReceiver");
             boolean done = false;
             while (!done) {
                 if(VERBOSE) Log.i(TAG, "Waiting for incomming RFCOMM message...");
@@ -452,14 +450,10 @@
                 mHandlerThread.join();
                 mHandlerThread = null;
             } catch (InterruptedException e) {}
-            if(mRilBtReceiverThread != null) try {
-                if(mRilBtReceiver != null) {
-                    mRilBtReceiver.shutdown();
-                    mRilBtReceiver = null;
-                }
-                mRilBtReceiverThread.join();
-                mRilBtReceiverThread = null;
-            } catch (InterruptedException e) {}
+            if (mRilBtReceiver != null) {
+                mRilBtReceiver.resetSapProxy();
+                mRilBtReceiver = null;
+            }
 
             if(mRfcommIn != null) try {
                 if(VERBOSE) Log.i(TAG, "Closing mRfcommIn...");
@@ -521,9 +515,9 @@
                  *  2) Send a RIL_SIM_SAP_CONNECT request to RILD
                  *  3) Send a RIL_SIM_RESET request and a connect confirm to the SAP client */
                 changeState(SAP_STATE.CONNECTING);
-                if(mRilBtReceiverThread != null) {
-                     // Open the RIL socket, and wait for the complete message: SAP_MSG_RIL_CONNECT
-                    mRilBtReceiverThread.start();
+                if (mRilBtReceiver != null) {
+                    // Notify the SapServer that we have connected to the SAP service
+                    mRilBtReceiver.sendRilConnectMessage();
                     // Don't send reply yet
                     reply = null;
                 } else {
@@ -640,6 +634,7 @@
             break;
         case SAP_PROXY_DEAD:
             if ((long) msg.obj == mRilBtReceiver.mSapProxyCookie.get()) {
+                mRilBtReceiver.notifyShutdown(); /* Only needed in case of a connection error */
                 mRilBtReceiver.resetSapProxy();
 
                 // todo: rild should be back up since message was sent with a delay. this is a hack.
@@ -856,25 +851,29 @@
                 + SapMessage.getMsgTypeName(sapMsg.getMsgType()));
 
         Log.d(TAG_HANDLER, "sendRilMessage: calling getSapProxy");
-        ISap sapProxy = mRilBtReceiver.getSapProxy();
-        if (sapProxy == null) {
-            Log.e(TAG_HANDLER, "sendRilMessage: Unable to send message to RIL; sapProxy is null");
-            sendClientMessage(new SapMessage(SapMessage.ID_ERROR_RESP));
-            return;
-        }
-
-        try {
-            sapMsg.send(sapProxy);
-            if (VERBOSE) {
-                Log.d(TAG_HANDLER, "sendRilMessage: sapMsg.callISapReq called successfully");
+        synchronized (mRilBtReceiver.getSapProxyLock()) {
+            ISap sapProxy = mRilBtReceiver.getSapProxy();
+            if (sapProxy == null) {
+                Log.e(TAG_HANDLER,
+                        "sendRilMessage: Unable to send message to RIL; sapProxy is null");
+                sendClientMessage(new SapMessage(SapMessage.ID_ERROR_RESP));
+                return;
             }
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG_HANDLER, "sendRilMessage: IllegalArgumentException", e);
-            sendClientMessage(new SapMessage(SapMessage.ID_ERROR_RESP));
-        } catch (RemoteException | RuntimeException e) {
-            Log.e(TAG_HANDLER, "sendRilMessage: Unable to send message to RIL", e);
-            sendClientMessage(new SapMessage(SapMessage.ID_ERROR_RESP));
-            mRilBtReceiver.resetSapProxy();
+
+            try {
+                sapMsg.send(sapProxy);
+                if (VERBOSE) {
+                    Log.d(TAG_HANDLER, "sendRilMessage: sapMsg.callISapReq called successfully");
+                }
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG_HANDLER, "sendRilMessage: IllegalArgumentException", e);
+                sendClientMessage(new SapMessage(SapMessage.ID_ERROR_RESP));
+            } catch (RemoteException | RuntimeException e) {
+                Log.e(TAG_HANDLER, "sendRilMessage: Unable to send message to RIL: " + e);
+                sendClientMessage(new SapMessage(SapMessage.ID_ERROR_RESP));
+                mRilBtReceiver.notifyShutdown(); /* Only needed in case of a connection error */
+                mRilBtReceiver.resetSapProxy();
+            }
         }
     }