12de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhoupackage com.google.android.experimental.bttraffic; 22de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 32de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport android.app.Service; 42de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport android.bluetooth.BluetoothAdapter; 52de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport android.bluetooth.BluetoothDevice; 62de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport android.bluetooth.BluetoothServerSocket; 72de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport android.bluetooth.BluetoothSocket; 82de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport android.content.Intent; 92de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport android.os.Bundle; 102de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport android.os.IBinder; 112de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport android.os.SystemClock; 122de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport android.util.Log; 132de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 142de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.io.Closeable; 152de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.io.IOException; 162de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.io.InputStream; 172de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.io.OutputStream; 182de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.lang.Exception; 192de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.lang.Runtime; 202de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.lang.RuntimeException; 212de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.lang.Process; 222de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.nio.ByteBuffer; 232de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.util.Random; 242de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.util.Set; 252de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhouimport java.util.UUID; 262de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 272de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhoupublic class BTtraffic extends Service { 282de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public static final String TAG = "bttraffic"; 292de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou static final String SERVICE_NAME = "bttraffic"; 302de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou static final String SYS_SERVICE_NAME = "com.android.bluetooth"; 312de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou static final UUID SERVICE_UUID = UUID.fromString("5e8945b0-1234-5432-a5e2-0800200c9a67"); 322de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou volatile Thread mWorkerThread; 332de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou volatile boolean isShuttingDown = false; 342de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou volatile boolean isServer = false; 352de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 362de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public BTtraffic() {} 372de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 382de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou static void safeClose(Closeable closeable) { 392de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou try { 402de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou closeable.close(); 412de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } catch (IOException e) { 422de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Unable to close resource.\n"); 432de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 442de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 452de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 462de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou @Override 472de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public int onStartCommand(Intent intent, int flags, int startId) { 482de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (intent == null) { 492de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou stopSelf(); 502de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou return 0; 512de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 522de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if ("stop".equals(intent.getAction())) { 532de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou stopService(); 542de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } else if ("start".equals(intent.getAction())) { 552de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou startWorker(intent); 562de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } else { 572de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "unknown action: + " + intent.getAction()); 582de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 592de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou return 0; 602de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 612de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 622de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private void startWorker(Intent intent) { 632de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (mWorkerThread != null) { 642de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "worker thread already active"); 652de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou return; 662de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 672de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou isShuttingDown = false; 682de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou String remoteAddr = intent.getStringExtra("addr"); 692de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "startWorker: addr=" + remoteAddr); 702de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Runnable worker = 712de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou remoteAddr == null 722de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou ? new ListenerRunnable(this, intent) 732de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou : new SenderRunnable(this, remoteAddr, intent); 742de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou isServer = remoteAddr == null ? true: false; 752de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou mWorkerThread = new Thread(worker, "BTtrafficWorker"); 762de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou try { 772de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou startMonitor(); 782de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Monitor service started"); 792de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou mWorkerThread.start(); 802de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Worker thread started"); 812de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } catch (Exception e) { 822de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Failed to start service", e); 832de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 842de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 852de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 862de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private void startMonitor() 872de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou throws Exception { 882de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (isServer) { 892de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Start monitor on server"); 902de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou String[] startmonitorCmd = { 912de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou "/system/bin/am", 922de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou "startservice", 932de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou "-a", "start", 942de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou "-e", "java", SERVICE_NAME, 952de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou "-e", "hal", SYS_SERVICE_NAME, 962de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou "com.google.android.experimental.svcmonitor/.SvcMonitor" 972de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou }; 982de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Process ps = new ProcessBuilder() 992de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou .command(startmonitorCmd) 1002de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou .redirectErrorStream(true) 1012de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou .start(); 1022de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } else { 1032de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "No need to start SvcMonitor on client"); 1042de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1052de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1062de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1072de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private void stopMonitor() 1082de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou throws Exception { 1092de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (isServer) { 1102de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "StopMonitor on server"); 1112de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou String[] stopmonitorCmd = { 1122de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou "/system/bin/am", 1132de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou "startservice", 1142de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou "-a", "stop", 1152de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou "com.google.android.experimental.svcmonitor/.SvcMonitor" 1162de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou }; 1172de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Process ps = new ProcessBuilder() 1182de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou .command(stopmonitorCmd) 1192de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou .redirectErrorStream(true) 1202de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou .start(); 1212de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } else { 1222de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "No need to stop Svcmonitor on client"); 1232de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1242de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1252de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1262de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public void stopService() { 1272de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (mWorkerThread == null) { 1282de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "no active thread"); 1292de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou return; 1302de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1312de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1322de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou isShuttingDown = true; 1332de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1342de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou try { 1352de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou stopMonitor(); 1362de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } catch (Exception e) { 1372de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Unable to stop SvcMonitor!", e); 1382de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1392de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1402de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (Thread.currentThread() != mWorkerThread) { 1412de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou mWorkerThread.interrupt(); 1422de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Interrupting thread"); 1432de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou try { 1442de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou mWorkerThread.join(); 1452de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } catch (InterruptedException e) { 1462de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Unable to join thread!"); 1472de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1482de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1492de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1502de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou mWorkerThread = null; 1512de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou stopSelf(); 1522de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Service stopped"); 1532de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1542de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1552de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou @Override 1562de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public void onDestroy() { 1572de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou super.onDestroy(); 1582de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1592de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1602de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou @Override 1612de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public IBinder onBind(Intent intent) { 1622de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou throw new UnsupportedOperationException("Not yet implemented"); 1632de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1642de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1652de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public static class ListenerRunnable implements Runnable { 1662de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private final BTtraffic bttraffic; 1672de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private final boolean sendAck; 1682de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private Intent intent; 1692de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private final int maxbuffersize = 20 * 1024 * 1024; 1702de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1712de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public ListenerRunnable(BTtraffic bttraffic, Intent intent) { 1722de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou this.bttraffic = bttraffic; 1732de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou this.sendAck = intent.getBooleanExtra("ack", true); 1742de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou this.intent = intent; 1752de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1762de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1772de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou @Override 1782de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public void run() { 1792de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou BluetoothServerSocket serverSocket; 1802de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1812de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou try { 1822de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "getting server socket"); 1832de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou serverSocket = BluetoothAdapter.getDefaultAdapter() 1842de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou .listenUsingInsecureRfcommWithServiceRecord( 1852de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou SERVICE_NAME, SERVICE_UUID); 1862de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } catch (IOException e) { 1872de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "error creating server socket, stopping thread"); 1882de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou bttraffic.stopService(); 1892de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou return; 1902de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 1912de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1922de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "got server socket, starting accept loop"); 1932de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou BluetoothSocket socket = null; 1942de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou try { 1952de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "accepting"); 1962de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou socket = serverSocket.accept(); 1972de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 1982de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (!Thread.interrupted()) { 1992de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "accepted, listening"); 2002de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou doListening(socket.getInputStream(), socket.getOutputStream()); 2012de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "listen finished"); 2022de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2032de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } catch (IOException e) { 2042de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "error while accepting or listening", e); 2052de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } finally { 2062de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Linster interruped"); 2072de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "closing socket and stopping service"); 2082de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou safeClose(serverSocket); 2092de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou safeClose(socket); 2102de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (!bttraffic.isShuttingDown) 2112de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou bttraffic.stopService(); 2122de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2132de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 2142de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2152de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 2162de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private void doListening(InputStream inputStream, OutputStream outputStream) 2172de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou throws IOException { 2182de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou ByteBuffer byteBuffer = ByteBuffer.allocate(maxbuffersize); 2192de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 2202de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou while (!Thread.interrupted()) { 2212de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou readBytesIntoBuffer(inputStream, byteBuffer, 4); 2222de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou byteBuffer.flip(); 2232de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou int length = byteBuffer.getInt(); 2242de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (Thread.interrupted()) 2252de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou break; 2262de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou readBytesIntoBuffer(inputStream, byteBuffer, length); 2272de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 2282de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (sendAck) 2292de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou outputStream.write(0x55); 2302de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2312de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2322de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 2332de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou void readBytesIntoBuffer(InputStream inputStream, ByteBuffer byteBuffer, int numToRead) 2342de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou throws IOException { 2352de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou byteBuffer.clear(); 2362de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou while (true) { 2372de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou int position = byteBuffer.position(); 2382de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou int remaining = numToRead - position; 2392de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (remaining == 0) { 2402de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou break; 2412de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2422de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou int count = inputStream.read(byteBuffer.array(), position, remaining); 2432de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (count < 0) { 2442de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou throw new IOException("read the EOF"); 2452de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2462de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou byteBuffer.position(position + count); 2472de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2482de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2492de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2502de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 2512de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public static class SenderRunnable implements Runnable { 2522de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private final BTtraffic bttraffic; 2532de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private final String remoteAddr; 2542de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private final int pkgsize, period; 2552de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private final int defaultpkgsize = 1024; 2562de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private final int defaultperiod = 5000; 2572de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private static ByteBuffer lengthBuffer = ByteBuffer.allocate(4); 2582de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 2592de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public SenderRunnable(BTtraffic bttraffic, String remoteAddr, Intent intent) { 2602de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou this.bttraffic = bttraffic; 2612de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou this.remoteAddr = remoteAddr; 2622de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou this.pkgsize = intent.getIntExtra("size", defaultpkgsize); 2632de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou this.period = intent.getIntExtra("period", defaultperiod); 2642de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2652de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 2662de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou @Override 2672de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou public void run() { 2682de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou BluetoothDevice device = null; 2692de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou try { 2702de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr); 2712de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } catch (IllegalArgumentException e) { 2722de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Invalid BT MAC address!\n"); 2732de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2742de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (device == null) { 2752de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "can't find matching device, stopping thread and service"); 2762de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou bttraffic.stopService(); 2772de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou return; 2782de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2792de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 2802de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou BluetoothSocket socket = null; 2812de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou try { 2822de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "connecting to device with MAC addr: " + remoteAddr); 2832de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou socket = device.createInsecureRfcommSocketToServiceRecord(SERVICE_UUID); 2842de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou socket.connect(); 2852de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "connected, starting to send"); 2862de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou doSending(socket.getOutputStream()); 2872de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "send stopped, stopping service"); 2882de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } catch (Exception e) { 2892de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "error while sending", e); 2902de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } finally { 2912de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "finishing, closing thread and service"); 2922de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou safeClose(socket); 2932de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (!bttraffic.isShuttingDown) 2942de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou bttraffic.stopService(); 2952de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2962de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 2972de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 2982de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private void doSending(OutputStream outputStream) throws IOException { 2992de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.w(TAG, "doSending"); 3002de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou try { 3012de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Random random = new Random(System.currentTimeMillis()); 3022de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 3032de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou byte[] bytes = new byte[pkgsize]; 3042de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou random.nextBytes(bytes); 3052de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou while (!Thread.interrupted()) { 3062de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou writeBytes(outputStream, bytes.length); 3072de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou outputStream.write(bytes, 0, bytes.length); 3082de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (period < 0) 3092de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou break; 3102de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou if (period == 0) 3112de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou continue; 3122de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 3132de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou SystemClock.sleep(period); 3142de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 3152de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "Sender interrupted"); 3162de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } catch (IOException e) { 3172de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou Log.d(TAG, "doSending got error", e); 3182de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 3192de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 3202de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 3212de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou private static void writeBytes(OutputStream outputStream, int value) throws IOException { 3222de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou lengthBuffer.putInt(value); 3232de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou lengthBuffer.flip(); 3242de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou outputStream.write(lengthBuffer.array(), lengthBuffer.position(), lengthBuffer.limit()); 3252de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 3262de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou } 3272de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou 3282de4b74d80edd8a8ee063980c6eb608369c5f81aYuchao Zhou} 329