Merge "Null pointer exception in SocketAcceptThread of BluetoothPbapService." into jb-mr2-dev
diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapService.java b/src/com/android/bluetooth/pbap/BluetoothPbapService.java
index 49e19e5..a45bc9a 100755
--- a/src/com/android/bluetooth/pbap/BluetoothPbapService.java
+++ b/src/com/android/bluetooth/pbap/BluetoothPbapService.java
@@ -297,10 +297,6 @@
 
         super.onDestroy();
         setState(BluetoothPbap.STATE_DISCONNECTED, BluetoothPbap.RESULT_CANCELED);
-        if (mWakeLock != null) {
-            mWakeLock.release();
-            mWakeLock = null;
-        }
         closeService();
         if(mSessionStatusHandler != null) {
             mSessionStatusHandler.removeCallbacksAndMessages(null);
@@ -326,11 +322,12 @@
     private final boolean initSocket() {
         if (VERBOSE) Log.v(TAG, "Pbap Service initSocket");
 
-        boolean initSocketOK = true;
+        boolean initSocketOK = false;
         final int CREATE_RETRY_TIME = 10;
 
         // It's possible that create will fail in some cases. retry for 10 times
         for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) {
+            initSocketOK = true;
             try {
                 // It is mandatory for PSE to support initiation of bonding and
                 // encryption.
@@ -350,20 +347,24 @@
                     Log.w(TAG, "initServerSocket failed as BT is (being) turned off");
                     break;
                 }
-                synchronized (this) {
-                    try {
-                        if (VERBOSE) Log.v(TAG, "wait 300 ms");
-                        Thread.sleep(300);
-                    } catch (InterruptedException e) {
-                        Log.e(TAG, "socketAcceptThread thread was interrupted (3)");
-                        mInterrupted = true;
-                    }
+                try {
+                    if (VERBOSE) Log.v(TAG, "wait 300 ms");
+                    Thread.sleep(300);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "socketAcceptThread thread was interrupted (3)");
+                    break;
                 }
             } else {
                 break;
             }
         }
 
+        if (mInterrupted) {
+            initSocketOK = false;
+            // close server socket to avoid resource leakage
+            closeServerSocket();
+        }
+
         if (initSocketOK) {
             if (VERBOSE) Log.v(TAG, "Succeed to create listening socket ");
 
@@ -373,21 +374,26 @@
         return initSocketOK;
     }
 
-    private final void closeSocket(boolean server, boolean accept) throws IOException {
-        if (server == true) {
-            // Stop the possible trying to init serverSocket
-            mInterrupted = true;
-
-            if (mServerSocket != null) {
+    private final synchronized void closeServerSocket() {
+        // exit SocketAcceptThread early
+        if (mServerSocket != null) {
+            try {
+                // this will cause mServerSocket.accept() return early with IOException
                 mServerSocket.close();
                 mServerSocket = null;
+            } catch (IOException ex) {
+                Log.e(TAG, "Close Server Socket error: " + ex);
             }
         }
+    }
 
-        if (accept == true) {
-            if (mConnSocket != null) {
+    private final synchronized void closeConnectionSocket() {
+        if (mConnSocket != null) {
+            try {
                 mConnSocket.close();
                 mConnSocket = null;
+            } catch (IOException e) {
+                Log.e(TAG, "Close Connection Socket error: " + e.toString());
             }
         }
     }
@@ -395,11 +401,9 @@
     private final void closeService() {
         if (VERBOSE) Log.v(TAG, "Pbap Service closeService in");
 
-        try {
-            closeSocket(true, true);
-        } catch (IOException ex) {
-            Log.e(TAG, "CloseSocket error: " + ex);
-        }
+        // exit initSocket early
+        mInterrupted = true;
+        closeServerSocket();
 
         if (mAcceptThread != null) {
             try {
@@ -410,11 +414,19 @@
                 Log.w(TAG, "mAcceptThread close error" + ex);
             }
         }
+
+        if (mWakeLock != null) {
+            mWakeLock.release();
+            mWakeLock = null;
+        }
+
         if (mServerSession != null) {
             mServerSession.close();
             mServerSession = null;
         }
 
+        closeConnectionSocket();
+
         mHasStarted = false;
         if (mStartId != -1 && stopSelfResult(mStartId)) {
             if (VERBOSE) Log.v(TAG, "successfully stopped pbap service");
@@ -473,12 +485,8 @@
 
         mAcceptThread = null;
 
-        try {
-            closeSocket(false, true);
-	    mConnSocket = null;
-        } catch (IOException e) {
-            Log.e(TAG, "closeSocket error: " + e.toString());
-        }
+        closeConnectionSocket();
+
         // Last obex transaction is finished, we start to listen for incoming
         // connection again
         if (mAdapter.isEnabled()) {
@@ -516,9 +524,9 @@
 
         @Override
         public void run() {
+            BluetoothServerSocket serverSocket;
             if (mServerSocket == null) {
                 if (!initSocket()) {
-                    closeService();
                     return;
                 }
             }
@@ -526,10 +534,21 @@
             while (!stopped) {
                 try {
                     if (VERBOSE) Log.v(TAG, "Accepting socket connection...");
-                    mConnSocket = mServerSocket.accept();
+                    serverSocket = mServerSocket;
+                    if (serverSocket == null) {
+                        Log.w(TAG, "mServerSocket is null");
+                        break;
+                    }
+                    mConnSocket = serverSocket.accept();
                     if (VERBOSE) Log.v(TAG, "Accepted socket connection...");
 
-                    mRemoteDevice = mConnSocket.getRemoteDevice();
+                    synchronized (BluetoothPbapService.this) {
+                        if (mConnSocket == null) {
+                            Log.w(TAG, "mConnSocket is null");
+                            break;
+                        }
+                        mRemoteDevice = mConnSocket.getRemoteDevice();
+                    }
                     if (mRemoteDevice == null) {
                         Log.i(TAG, "getRemoteDevice() = null");
                         break;
@@ -783,12 +802,9 @@
                             mServerSession.close();
                             mServerSession = null;
                         }
-                        try {
-                            closeSocket(false, true);
-                            mConnSocket = null;
-                        } catch (IOException ex) {
-                            Log.e(TAG, "Caught the error: " + ex);
-                        }
+
+                        closeConnectionSocket();
+
                         setState(BluetoothPbap.STATE_DISCONNECTED, BluetoothPbap.RESULT_CANCELED);
                         break;
                     default: