title: Multiple bluetooth socket connect/close operations reboot android phones
body: <p>We are using android phones to communicate with sensors via bluetooth. The phone needs to connect the sensor periodically to collect physiological data and between two connections the sensors can be switched off automatically to save power. </p>
  
  <p>Now the problem is: after around 500 times, the system reboots. We then wrote a small piece of test program to simulate the whole process. The small test program, too, crashes the android phone. </p>
  
  <p>Can anybody please help me on this ? Thanks! Here is the small test program. </p>
  
  <pre><code>package zhb.test.MhubTestBtConnect;
  
  import java.io.IOException;
  import java.util.Date;
  import java.util.UUID;
  
  
  import android.app.Activity;
  import android.bluetooth.BluetoothAdapter;
  import android.bluetooth.BluetoothDevice;
  import android.bluetooth.BluetoothSocket;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.Looper;
  import android.os.Message;
  import android.util.Log;
  import android.view.View;
  import android.view.View.OnClickListener;
  import android.widget.Button;
  import android.widget.EditText;
  import android.widget.TextView;
  
  public class MhubTestBtConnect extends Activity implements OnClickListener{
      /** Called when the activity is first created. */
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main);
  
          Button btnStart = (Button) findViewById(R.id.btn_start_test);
          btnStart.setOnClickListener(this);
          Button btnStop = (Button) findViewById(R.id.btn_stop_test);
          btnStop.setOnClickListener(this);
  
          fBeginView = (TextView) findViewById(R.id.begin_time);
          fBeginView.setText("off line");
          fEndView = (TextView) findViewById(R.id.end_time);
          fEndView.setText("off line");
          fShowView = (TextView) findViewById(R.id.show_status);
          fShowView.setText("off line");
  
          fShowRunTimesView = (TextView) findViewById(R.id.show_times_status);
          fShowRunTimesView.setText("off line");
  
  
          fInputMac = (EditText) findViewById(R.id.edit_add_mac);
          fInputMac.setText("00:19:5D:24:CB:A9");
          fDisconnectGap = (EditText) findViewById(R.id.edit_disconnect_gap);
          fDisconnectGap.setText("500");
          fconnectGap = (EditText) findViewById(R.id.edit_connect_gap);
          fconnectGap.setText("1000");
  
          fRunning = false;        
      }
  
      @Override
      public void onClick(View v)
      {
          switch ( v.getId() )
          {
              case R.id.btn_start_test:
                  start();
                  break;
              case R.id.btn_stop_test:
                  stop();
                  break;
              default:
                  break;
          }       
      }
  
      private synchronized void start()
      {
          if ( fRunning == false )
          {
              fRunning = true;            
  
  
              fMac = fInputMac.getText().toString().toUpperCase();
              fConnectRunnable = new ConnectRunnable();           
              fBeginView.setText(new Date().toLocaleString());
  
              fConnectTimes = 0;
              fRunOkTimes = 0;
              new Thread(fConnectRunnable).start();
          }
      }
  
      private synchronized void stop()
      {
          if ( fRunning == true )
          {
              fRunning = false;
  
              fConnectRunnable.cancel();
              try
              {
                  Thread.sleep(500);
              }
              catch (InterruptedException exception)
              {
                  exception.printStackTrace();
              }
  
  
              fEndView.setText(new Date().toLocaleString());
          }
      }   
  
      private void connect()
      {
          Log.d(TAG,"---------- run "+fConnectTimes++ +" times");
          String UUID_STRING = "00001101-0000-1000-8000-00805F9B34FB";
          // may throws exception
          UUID uuid = UUID.fromString(UUID_STRING);
  
          // get adapter
          BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();        
  
          // get remote device
          BluetoothDevice btDevice = adapter.getRemoteDevice(fMac);
          if ( btDevice == null )
          {
              Log.e(TAG,"can't get remote device from given MAC : " + fMac);
              return;
          }
          int runResult = 0;
          // may throws exception
          fBtSocket = null;
          try
          {
              fBtSocket = btDevice.createRfcommSocketToServiceRecord(uuid);
              if ( adapter.isDiscovering() == true ) 
              {
                  adapter.cancelDiscovery();
                  Log.d(TAG,"cancel discover");
              }
  
              fBtSocket.connect();
              runResult = 1;
              Log.d(TAG,"connect socket OK");
              Log.d(TAG,"---------- run OK "+fRunOkTimes++ +" times");
          }
          catch (IOException exception)
          {       
              //adapter.cancelDiscovery();
              Log.d(TAG,"connect socket error",exception);
              if ( fBtSocket != null )
              {
                  try
                  {
                      fBtSocket.close();
                  }
                  catch (IOException exception1)
                  {
                      Log.d(TAG,"close socket error",exception1);
                  }
              }
              else
              {
                  Log.d(TAG,"create socket NULL");
              }
  
              btDevice = null;
              //update ui
              Message msgRun = new Message();
              msgRun.what = R.id.show_status;
              msgRun.arg1 = SV_START_RUN;
              msgRun.arg2 = runResult;
              fMessHandler.sendMessage(msgRun);
          }
  
          //Note: You should always ensure that the device is not performing device discovery when you call connect(). 
          //If discovery is in progress, then the connection attempt will be significantly slowed and is more likely to fail.
          //adapter.cancelDiscovery();
      }
      private void close()
      {
          //update ui
          Message msgShut = new Message();
          msgShut.what = R.id.show_status;
          msgShut.arg1 = SV_SHUT_DOWN;
          fMessHandler.sendMessage(msgShut);
  
          if ( fBtSocket != null )
          {
              Log.d(TAG,"close socket");
              try
              {
                  fBtSocket.close();
              }
              catch (IOException exception1)
              {
                  Log.d(TAG,"close socket error",exception1);
              }
              fBtSocket = null;
          }
      }   
      private Handler fMessHandler = new Handler()
      {
          public void handleMessage(android.os.Message msg)
          {
              switch ( msg.what )
              {
                  case R.id.show_status:
                      if ( msg.arg1 == SV_START_RUN )
                      {
                          if ( msg.arg2 == 1)
                              fShowView.setText("run OK");
                          else 
                              fShowView.setText("run Failed");
  
                          fShowRunTimesView.setText("run "+fConnectTimes+", OK "+fRunOkTimes);
                      }
                      else if ( msg.arg1 == SV_SHUT_DOWN )
                          fShowView.setText("shut down ...");
  
                      break;
  
                  default:
                      break;
              }
          };
      };
  
      private long fConnectTimes;
      private long fRunOkTimes;
      private static final String TAG = "..MhubTestBtConnect";
      private BluetoothSocket fBtSocket;
  
      private ConnectRunnable fConnectRunnable;
      private String fMac;
      private boolean fRunning;
  
      private TextView fBeginView;
      private TextView fEndView;
      private TextView fShowView;
      private TextView fShowRunTimesView;
      private EditText fInputMac;
      private EditText fDisconnectGap;
      private EditText fconnectGap;
  
      private static final int SV_START_RUN = 1;
      private static final int SV_SHUT_DOWN = 2;
  
      private class ConnectRunnable implements Runnable
      {
          public ConnectRunnable()
          {           
              fCancelled = false;
          }
          @Override
          public void run()
          {           
              if (Looper.myLooper() == null) {
                  Looper.prepare();
              }
  
              long afterConnectSleep = 500;
              long afterCloseSleep = 1000;
              try
              {
                  afterCloseSleep = Integer.parseInt(fconnectGap.getText().toString());
                  afterConnectSleep = Integer.parseInt(fDisconnectGap.getText().toString());
              }
              catch(Exception exception)
              {
                  afterConnectSleep = 500;
                  afterCloseSleep = 1000;
              }
              while ( fCancelled == false )
              {               
                  connect();
                  try
                  {
                      Thread.sleep(afterConnectSleep);
                  }
                  catch (InterruptedException exception)
                  {
                      exception.printStackTrace();
                  }
  
                  close();
                  try
                  {
                      Thread.sleep(afterCloseSleep);
                  }
                  catch (InterruptedException exception)
                  {
                      exception.printStackTrace();
                  }
              }
          }
  
          public void cancel()
          {
              fCancelled = true;
          }
          private boolean fCancelled;
  
      }
  }
  </code></pre>