1 package com.android.bluetooth.sap; 2 3 import android.annotation.TargetApi; 4 import android.app.AlarmManager; 5 import android.app.PendingIntent; 6 import android.bluetooth.BluetoothAdapter; 7 import android.bluetooth.BluetoothDevice; 8 import android.bluetooth.BluetoothProfile; 9 import android.bluetooth.BluetoothSap; 10 import android.bluetooth.BluetoothServerSocket; 11 import android.bluetooth.BluetoothSocket; 12 import android.bluetooth.BluetoothUuid; 13 import android.bluetooth.IBluetoothSap; 14 import android.content.BroadcastReceiver; 15 import android.content.Context; 16 import android.content.Intent; 17 import android.content.IntentFilter; 18 import android.os.Build; 19 import android.os.Handler; 20 import android.os.Message; 21 import android.os.ParcelUuid; 22 import android.os.PowerManager; 23 import android.text.TextUtils; 24 import android.util.Log; 25 26 import com.android.bluetooth.BluetoothMetricsProto; 27 import com.android.bluetooth.R; 28 import com.android.bluetooth.Utils; 29 import com.android.bluetooth.btservice.AdapterService; 30 import com.android.bluetooth.btservice.MetricsLogger; 31 import com.android.bluetooth.btservice.ProfileService; 32 import com.android.bluetooth.sdp.SdpManager; 33 import com.android.internal.annotations.VisibleForTesting; 34 35 import java.io.IOException; 36 import java.util.ArrayList; 37 import java.util.List; 38 import java.util.Set; 39 40 @TargetApi(Build.VERSION_CODES.ECLAIR) 41 public class SapService extends ProfileService { 42 43 private static final String SDP_SAP_SERVICE_NAME = "SIM Access"; 44 private static final int SDP_SAP_VERSION = 0x0102; 45 private static final String TAG = "SapService"; 46 public static final boolean DEBUG = false; 47 public static final boolean VERBOSE = false; 48 49 /* Message ID's */ 50 private static final int START_LISTENER = 1; 51 private static final int USER_TIMEOUT = 2; 52 private static final int SHUTDOWN = 3; 53 54 public static final int MSG_SERVERSESSION_CLOSE = 5000; 55 public static final int MSG_SESSION_ESTABLISHED = 5001; 56 public static final int MSG_SESSION_DISCONNECTED = 5002; 57 58 public static final int MSG_ACQUIRE_WAKE_LOCK = 5005; 59 public static final int MSG_RELEASE_WAKE_LOCK = 5006; 60 61 public static final int MSG_CHANGE_STATE = 5007; 62 63 /* Each time a transaction between the SIM and the BT Client is detected a wakelock is taken. 64 * After an idle period of RELEASE_WAKE_LOCK_DELAY ms the wakelock is released. 65 * 66 * NOTE: While connected the the Nokia 616 car-kit it was noticed that the carkit do 67 * TRANSFER_APDU_REQ with 20-30 seconds interval, and it sends no requests less than 1 sec 68 * apart. Additionally the responses from the RIL seems to come within 100 ms, hence a 69 * one second timeout should be enough. 70 */ 71 private static final int RELEASE_WAKE_LOCK_DELAY = 1000; 72 73 /* Intent indicating timeout for user confirmation. */ 74 public static final String USER_CONFIRM_TIMEOUT_ACTION = 75 "com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT"; 76 private static final int USER_CONFIRM_TIMEOUT_VALUE = 25000; 77 78 private PowerManager.WakeLock mWakeLock = null; 79 private BluetoothAdapter mAdapter; 80 private SocketAcceptThread mAcceptThread = null; 81 private BluetoothServerSocket mServerSocket = null; 82 private int mSdpHandle = -1; 83 private BluetoothSocket mConnSocket = null; 84 private BluetoothDevice mRemoteDevice = null; 85 private static String sRemoteDeviceName = null; 86 private volatile boolean mInterrupted; 87 private int mState; 88 private SapServer mSapServer = null; 89 private AlarmManager mAlarmManager = null; 90 private boolean mRemoveTimeoutMsg = false; 91 92 private boolean mIsWaitingAuthorization = false; 93 private boolean mIsRegistered = false; 94 95 private static SapService sSapService; 96 97 private static final ParcelUuid[] SAP_UUIDS = { 98 BluetoothUuid.SAP, 99 }; 100 101 SapService()102 public SapService() { 103 mState = BluetoothSap.STATE_DISCONNECTED; 104 } 105 106 /*** 107 * Call this when ever an activity is detected to renew the wakelock 108 * 109 * @param messageHandler reference to the handler to notify 110 * - typically mSessionStatusHandler, but it cannot be accessed in a static manner. 111 */ notifyUpdateWakeLock(Handler messageHandler)112 public static void notifyUpdateWakeLock(Handler messageHandler) { 113 if (messageHandler != null) { 114 Message msg = Message.obtain(messageHandler); 115 msg.what = MSG_ACQUIRE_WAKE_LOCK; 116 msg.sendToTarget(); 117 } 118 } 119 removeSdpRecord()120 private void removeSdpRecord() { 121 if (mAdapter != null && mSdpHandle >= 0 && SdpManager.getDefaultManager() != null) { 122 if (VERBOSE) { 123 Log.d(TAG, "Removing SDP record handle: " + mSdpHandle); 124 } 125 boolean status = SdpManager.getDefaultManager().removeSdpRecord(mSdpHandle); 126 mSdpHandle = -1; 127 } 128 } 129 startRfcommSocketListener()130 private void startRfcommSocketListener() { 131 if (VERBOSE) { 132 Log.v(TAG, "Sap Service startRfcommSocketListener"); 133 } 134 135 if (mAcceptThread == null) { 136 mAcceptThread = new SocketAcceptThread(); 137 mAcceptThread.setName("SapAcceptThread"); 138 mAcceptThread.start(); 139 } 140 } 141 142 private static final int CREATE_RETRY_TIME = 10; 143 initSocket()144 private boolean initSocket() { 145 if (VERBOSE) { 146 Log.v(TAG, "Sap Service initSocket"); 147 } 148 149 boolean initSocketOK = false; 150 151 // It's possible that create will fail in some cases. retry for 10 times 152 for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) { 153 initSocketOK = true; 154 try { 155 // It is mandatory for MSE to support initiation of bonding and encryption. 156 // TODO: Consider reusing the mServerSocket - it is indented to be reused 157 // for multiple connections. 158 mServerSocket = mAdapter.listenUsingRfcommOn( 159 BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, true, true); 160 removeSdpRecord(); 161 mSdpHandle = SdpManager.getDefaultManager() 162 .createSapsRecord(SDP_SAP_SERVICE_NAME, mServerSocket.getChannel(), 163 SDP_SAP_VERSION); 164 } catch (IOException e) { 165 Log.e(TAG, "Error create RfcommServerSocket ", e); 166 initSocketOK = false; 167 } 168 169 if (!initSocketOK) { 170 // Need to break out of this loop if BT is being turned off. 171 if (mAdapter == null) { 172 break; 173 } 174 int state = mAdapter.getState(); 175 if ((state != BluetoothAdapter.STATE_TURNING_ON) && (state 176 != BluetoothAdapter.STATE_ON)) { 177 Log.w(TAG, "initServerSocket failed as BT is (being) turned off"); 178 break; 179 } 180 try { 181 if (VERBOSE) { 182 Log.v(TAG, "wait 300 ms"); 183 } 184 Thread.sleep(300); 185 } catch (InterruptedException e) { 186 Log.e(TAG, "socketAcceptThread thread was interrupted (3)", e); 187 } 188 } else { 189 break; 190 } 191 } 192 193 if (initSocketOK) { 194 if (VERBOSE) { 195 Log.v(TAG, "Succeed to create listening socket "); 196 } 197 198 } else { 199 Log.e(TAG, "Error to create listening socket after " + CREATE_RETRY_TIME + " try"); 200 } 201 return initSocketOK; 202 } 203 closeServerSocket()204 private synchronized void closeServerSocket() { 205 // exit SocketAcceptThread early 206 if (mServerSocket != null) { 207 try { 208 // this will cause mServerSocket.accept() return early with IOException 209 mServerSocket.close(); 210 mServerSocket = null; 211 } catch (IOException ex) { 212 Log.e(TAG, "Close Server Socket error: ", ex); 213 } 214 } 215 } 216 closeConnectionSocket()217 private synchronized void closeConnectionSocket() { 218 if (mConnSocket != null) { 219 try { 220 mConnSocket.close(); 221 mConnSocket = null; 222 } catch (IOException e) { 223 Log.e(TAG, "Close Connection Socket error: ", e); 224 } 225 } 226 } 227 closeService()228 private void closeService() { 229 if (VERBOSE) { 230 Log.v(TAG, "SAP Service closeService in"); 231 } 232 233 // exit initSocket early 234 mInterrupted = true; 235 closeServerSocket(); 236 237 if (mAcceptThread != null) { 238 try { 239 mAcceptThread.shutdown(); 240 mAcceptThread.join(); 241 mAcceptThread = null; 242 } catch (InterruptedException ex) { 243 Log.w(TAG, "mAcceptThread close error", ex); 244 } 245 } 246 247 if (mWakeLock != null) { 248 mSessionStatusHandler.removeMessages(MSG_ACQUIRE_WAKE_LOCK); 249 mSessionStatusHandler.removeMessages(MSG_RELEASE_WAKE_LOCK); 250 mWakeLock.release(); 251 mWakeLock = null; 252 } 253 254 closeConnectionSocket(); 255 256 if (VERBOSE) { 257 Log.v(TAG, "SAP Service closeService out"); 258 } 259 } 260 startSapServerSession()261 private void startSapServerSession() throws IOException { 262 if (VERBOSE) { 263 Log.v(TAG, "Sap Service startSapServerSession"); 264 } 265 266 // acquire the wakeLock before start SAP transaction thread 267 if (mWakeLock == null) { 268 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 269 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "StartingSapTransaction"); 270 mWakeLock.setReferenceCounted(false); 271 mWakeLock.acquire(); 272 } 273 274 /* Start the SAP I/O thread and associate with message handler */ 275 mSapServer = new SapServer(mSessionStatusHandler, this, mConnSocket.getInputStream(), 276 mConnSocket.getOutputStream()); 277 mSapServer.start(); 278 /* Warning: at this point we most likely have already handled the initial connect 279 * request from the SAP client, hence we need to be prepared to handle the 280 * response. (the SapHandler should have been started before this point)*/ 281 282 mSessionStatusHandler.removeMessages(MSG_RELEASE_WAKE_LOCK); 283 mSessionStatusHandler.sendMessageDelayed( 284 mSessionStatusHandler.obtainMessage(MSG_RELEASE_WAKE_LOCK), 285 RELEASE_WAKE_LOCK_DELAY); 286 287 if (VERBOSE) { 288 Log.v(TAG, "startSapServerSession() success!"); 289 } 290 } 291 stopSapServerSession()292 private void stopSapServerSession() { 293 294 /* When we reach this point, the SapServer is closed down, and the client is 295 * supposed to close the RFCOMM connection. */ 296 if (VERBOSE) { 297 Log.v(TAG, "SAP Service stopSapServerSession"); 298 } 299 300 mAcceptThread = null; 301 closeConnectionSocket(); 302 closeServerSocket(); 303 304 setState(BluetoothSap.STATE_DISCONNECTED); 305 306 if (mWakeLock != null) { 307 mWakeLock.release(); 308 mWakeLock = null; 309 } 310 311 // Last SAP transaction is finished, we start to listen for incoming 312 // rfcomm connection again 313 if (mAdapter.isEnabled()) { 314 startRfcommSocketListener(); 315 } 316 } 317 318 /** 319 * A thread that runs in the background waiting for remote rfcomm 320 * connect.Once a remote socket connected, this thread shall be 321 * shutdown.When the remote disconnect,this thread shall run again waiting 322 * for next request. 323 */ 324 private class SocketAcceptThread extends Thread { 325 326 private boolean mStopped = false; 327 328 @Override run()329 public void run() { 330 BluetoothServerSocket serverSocket; 331 if (mServerSocket == null) { 332 if (!initSocket()) { 333 return; 334 } 335 } 336 337 while (!mStopped) { 338 try { 339 if (VERBOSE) { 340 Log.v(TAG, "Accepting socket connection..."); 341 } 342 serverSocket = mServerSocket; 343 if (serverSocket == null) { 344 Log.w(TAG, "mServerSocket is null"); 345 break; 346 } 347 mConnSocket = mServerSocket.accept(); 348 if (VERBOSE) { 349 Log.v(TAG, "Accepted socket connection..."); 350 } 351 synchronized (SapService.this) { 352 if (mConnSocket == null) { 353 Log.w(TAG, "mConnSocket is null"); 354 break; 355 } 356 mRemoteDevice = mConnSocket.getRemoteDevice(); 357 } 358 if (mRemoteDevice == null) { 359 Log.i(TAG, "getRemoteDevice() = null"); 360 break; 361 } 362 363 sRemoteDeviceName = mRemoteDevice.getName(); 364 // In case getRemoteName failed and return null 365 if (TextUtils.isEmpty(sRemoteDeviceName)) { 366 sRemoteDeviceName = getString(R.string.defaultname); 367 } 368 int permission = mRemoteDevice.getSimAccessPermission(); 369 370 if (VERBOSE) { 371 Log.v(TAG, "getSimAccessPermission() = " + permission); 372 } 373 374 if (permission == BluetoothDevice.ACCESS_ALLOWED) { 375 try { 376 if (VERBOSE) { 377 Log.v(TAG, "incoming connection accepted from: " + sRemoteDeviceName 378 + " automatically as trusted device"); 379 } 380 startSapServerSession(); 381 } catch (IOException ex) { 382 Log.e(TAG, "catch exception starting obex server session", ex); 383 } 384 } else if (permission != BluetoothDevice.ACCESS_REJECTED) { 385 Intent intent = 386 new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST); 387 intent.setPackage(getString(R.string.pairing_ui_package)); 388 intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 389 BluetoothDevice.REQUEST_TYPE_SIM_ACCESS); 390 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice); 391 intent.putExtra(BluetoothDevice.EXTRA_PACKAGE_NAME, getPackageName()); 392 393 mIsWaitingAuthorization = true; 394 setUserTimeoutAlarm(); 395 sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 396 397 if (VERBOSE) { 398 Log.v(TAG, "waiting for authorization for connection from: " 399 + sRemoteDeviceName); 400 } 401 402 } else { 403 // Close RFCOMM socket for current connection and start listening 404 // again for new connections. 405 Log.w(TAG, "Can't connect with " + sRemoteDeviceName 406 + " as access is rejected"); 407 if (mSessionStatusHandler != null) { 408 mSessionStatusHandler.sendEmptyMessage(MSG_SERVERSESSION_CLOSE); 409 } 410 } 411 mStopped = true; // job done ,close this thread; 412 } catch (IOException ex) { 413 mStopped = true; 414 if (VERBOSE) { 415 Log.v(TAG, "Accept exception: ", ex); 416 } 417 } 418 } 419 } 420 shutdown()421 void shutdown() { 422 mStopped = true; 423 interrupt(); 424 } 425 } 426 427 private final Handler mSessionStatusHandler = new Handler() { 428 @Override 429 public void handleMessage(Message msg) { 430 if (VERBOSE) { 431 Log.v(TAG, "Handler(): got msg=" + msg.what); 432 } 433 434 switch (msg.what) { 435 case START_LISTENER: 436 if (mAdapter.isEnabled()) { 437 startRfcommSocketListener(); 438 } 439 break; 440 case USER_TIMEOUT: 441 if (mIsWaitingAuthorization) { 442 sendCancelUserConfirmationIntent(mRemoteDevice); 443 cancelUserTimeoutAlarm(); 444 mIsWaitingAuthorization = false; 445 stopSapServerSession(); // And restart RfcommListener if needed 446 } 447 break; 448 case MSG_SERVERSESSION_CLOSE: 449 stopSapServerSession(); 450 break; 451 case MSG_SESSION_ESTABLISHED: 452 break; 453 case MSG_SESSION_DISCONNECTED: 454 // handled elsewhere 455 break; 456 case MSG_ACQUIRE_WAKE_LOCK: 457 if (VERBOSE) { 458 Log.i(TAG, "Acquire Wake Lock request message"); 459 } 460 if (mWakeLock == null) { 461 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 462 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 463 "StartingObexMapTransaction"); 464 mWakeLock.setReferenceCounted(false); 465 } 466 if (!mWakeLock.isHeld()) { 467 mWakeLock.acquire(); 468 if (DEBUG) { 469 Log.i(TAG, " Acquired Wake Lock by message"); 470 } 471 } 472 mSessionStatusHandler.removeMessages(MSG_RELEASE_WAKE_LOCK); 473 mSessionStatusHandler.sendMessageDelayed( 474 mSessionStatusHandler.obtainMessage(MSG_RELEASE_WAKE_LOCK), 475 RELEASE_WAKE_LOCK_DELAY); 476 break; 477 case MSG_RELEASE_WAKE_LOCK: 478 if (VERBOSE) { 479 Log.i(TAG, "Release Wake Lock request message"); 480 } 481 if (mWakeLock != null) { 482 mWakeLock.release(); 483 if (DEBUG) { 484 Log.i(TAG, " Released Wake Lock by message"); 485 } 486 } 487 break; 488 case MSG_CHANGE_STATE: 489 if (DEBUG) { 490 Log.d(TAG, "change state message: newState = " + msg.arg1); 491 } 492 setState(msg.arg1); 493 break; 494 case SHUTDOWN: 495 /* Ensure to call close from this handler to avoid starting new stuff 496 because of pending messages */ 497 closeService(); 498 break; 499 default: 500 break; 501 } 502 } 503 }; 504 setState(int state)505 private void setState(int state) { 506 setState(state, BluetoothSap.RESULT_SUCCESS); 507 } 508 setState(int state, int result)509 private synchronized void setState(int state, int result) { 510 if (state != mState) { 511 if (DEBUG) { 512 Log.d(TAG, "Sap state " + mState + " -> " + state + ", result = " + result); 513 } 514 if (state == BluetoothProfile.STATE_CONNECTED) { 515 MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.SAP); 516 } 517 int prevState = mState; 518 mState = state; 519 Intent intent = new Intent(BluetoothSap.ACTION_CONNECTION_STATE_CHANGED); 520 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 521 intent.putExtra(BluetoothProfile.EXTRA_STATE, mState); 522 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice); 523 sendBroadcast(intent, BLUETOOTH_PERM); 524 } 525 } 526 getState()527 public int getState() { 528 return mState; 529 } 530 getRemoteDevice()531 public BluetoothDevice getRemoteDevice() { 532 return mRemoteDevice; 533 } 534 getRemoteDeviceName()535 public static String getRemoteDeviceName() { 536 return sRemoteDeviceName; 537 } 538 disconnect(BluetoothDevice device)539 public boolean disconnect(BluetoothDevice device) { 540 boolean result = false; 541 synchronized (SapService.this) { 542 if (mRemoteDevice != null && mRemoteDevice.equals(device)) { 543 switch (mState) { 544 case BluetoothSap.STATE_CONNECTED: 545 closeConnectionSocket(); 546 setState(BluetoothSap.STATE_DISCONNECTED, BluetoothSap.RESULT_CANCELED); 547 result = true; 548 break; 549 default: 550 break; 551 } 552 } 553 } 554 return result; 555 } 556 getConnectedDevices()557 public List<BluetoothDevice> getConnectedDevices() { 558 List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 559 synchronized (this) { 560 if (mState == BluetoothSap.STATE_CONNECTED && mRemoteDevice != null) { 561 devices.add(mRemoteDevice); 562 } 563 } 564 return devices; 565 } 566 getDevicesMatchingConnectionStates(int[] states)567 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 568 List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); 569 Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); 570 int connectionState; 571 synchronized (this) { 572 for (BluetoothDevice device : bondedDevices) { 573 ParcelUuid[] featureUuids = device.getUuids(); 574 if (!BluetoothUuid.containsAnyUuid(featureUuids, SAP_UUIDS)) { 575 continue; 576 } 577 connectionState = getConnectionState(device); 578 for (int i = 0; i < states.length; i++) { 579 if (connectionState == states[i]) { 580 deviceList.add(device); 581 } 582 } 583 } 584 } 585 return deviceList; 586 } 587 getConnectionState(BluetoothDevice device)588 public int getConnectionState(BluetoothDevice device) { 589 synchronized (this) { 590 if (getState() == BluetoothSap.STATE_CONNECTED && getRemoteDevice().equals(device)) { 591 return BluetoothProfile.STATE_CONNECTED; 592 } else { 593 return BluetoothProfile.STATE_DISCONNECTED; 594 } 595 } 596 } 597 598 /** 599 * Set connection policy of the profile and disconnects it if connectionPolicy is 600 * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN} 601 * 602 * <p> The device should already be paired. 603 * Connection policy can be one of: 604 * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, 605 * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, 606 * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} 607 * 608 * @param device Paired bluetooth device 609 * @param connectionPolicy is the connection policy to set to for this profile 610 * @return true if connectionPolicy is set, false on error 611 */ setConnectionPolicy(BluetoothDevice device, int connectionPolicy)612 public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { 613 if (DEBUG) { 614 Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy); 615 } 616 enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, 617 "Need BLUETOOTH_PRIVILEGED permission"); 618 AdapterService.getAdapterService().getDatabase() 619 .setProfileConnectionPolicy(device, BluetoothProfile.SAP, connectionPolicy); 620 if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { 621 disconnect(device); 622 } 623 return true; 624 } 625 626 /** 627 * Get the connection policy of the profile. 628 * 629 * <p> The connection policy can be any of: 630 * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, 631 * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, 632 * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} 633 * 634 * @param device Bluetooth device 635 * @return connection policy of the device 636 * @hide 637 */ getConnectionPolicy(BluetoothDevice device)638 public int getConnectionPolicy(BluetoothDevice device) { 639 enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, 640 "Need BLUETOOTH_PRIVILEGED permission"); 641 return AdapterService.getAdapterService().getDatabase() 642 .getProfileConnectionPolicy(device, BluetoothProfile.SAP); 643 } 644 645 @Override initBinder()646 protected IProfileServiceBinder initBinder() { 647 return new SapBinder(this); 648 } 649 650 @Override start()651 protected boolean start() { 652 Log.v(TAG, "start()"); 653 IntentFilter filter = new IntentFilter(); 654 filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); 655 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 656 filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); 657 filter.addAction(USER_CONFIRM_TIMEOUT_ACTION); 658 659 try { 660 registerReceiver(mSapReceiver, filter); 661 mIsRegistered = true; 662 } catch (Exception e) { 663 Log.w(TAG, "Unable to register sap receiver", e); 664 } 665 mInterrupted = false; 666 mAdapter = BluetoothAdapter.getDefaultAdapter(); 667 // start RFCOMM listener 668 mSessionStatusHandler.sendMessage(mSessionStatusHandler.obtainMessage(START_LISTENER)); 669 setSapService(this); 670 return true; 671 } 672 673 @Override stop()674 protected boolean stop() { 675 Log.v(TAG, "stop()"); 676 if (!mIsRegistered) { 677 Log.i(TAG, "Avoid unregister when receiver it is not registered"); 678 return true; 679 } 680 setSapService(null); 681 try { 682 mIsRegistered = false; 683 unregisterReceiver(mSapReceiver); 684 } catch (Exception e) { 685 Log.w(TAG, "Unable to unregister sap receiver", e); 686 } 687 setState(BluetoothSap.STATE_DISCONNECTED, BluetoothSap.RESULT_CANCELED); 688 sendShutdownMessage(); 689 return true; 690 } 691 692 @Override cleanup()693 public void cleanup() { 694 setState(BluetoothSap.STATE_DISCONNECTED, BluetoothSap.RESULT_CANCELED); 695 closeService(); 696 if (mSessionStatusHandler != null) { 697 mSessionStatusHandler.removeCallbacksAndMessages(null); 698 } 699 } 700 701 /** 702 * Get the current instance of {@link SapService} 703 * 704 * @return current instance of {@link SapService} 705 */ 706 @VisibleForTesting getSapService()707 public static synchronized SapService getSapService() { 708 if (sSapService == null) { 709 Log.w(TAG, "getSapService(): service is null"); 710 return null; 711 } 712 if (!sSapService.isAvailable()) { 713 Log.w(TAG, "getSapService(): service is not available"); 714 return null; 715 } 716 return sSapService; 717 } 718 setSapService(SapService instance)719 private static synchronized void setSapService(SapService instance) { 720 if (DEBUG) { 721 Log.d(TAG, "setSapService(): set to: " + instance); 722 } 723 sSapService = instance; 724 } 725 setUserTimeoutAlarm()726 private void setUserTimeoutAlarm() { 727 if (DEBUG) { 728 Log.d(TAG, "setUserTimeOutAlarm()"); 729 } 730 cancelUserTimeoutAlarm(); 731 mRemoveTimeoutMsg = true; 732 Intent timeoutIntent = new Intent(USER_CONFIRM_TIMEOUT_ACTION); 733 PendingIntent pIntent = PendingIntent.getBroadcast(this, 0, timeoutIntent, 0); 734 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 735 System.currentTimeMillis() + USER_CONFIRM_TIMEOUT_VALUE, pIntent); 736 } 737 cancelUserTimeoutAlarm()738 private void cancelUserTimeoutAlarm() { 739 if (DEBUG) { 740 Log.d(TAG, "cancelUserTimeOutAlarm()"); 741 } 742 if (mAlarmManager == null) { 743 mAlarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE); 744 } 745 if (mRemoveTimeoutMsg) { 746 Intent timeoutIntent = new Intent(USER_CONFIRM_TIMEOUT_ACTION); 747 PendingIntent sender = PendingIntent.getBroadcast(this, 0, timeoutIntent, 0); 748 mAlarmManager.cancel(sender); 749 mRemoveTimeoutMsg = false; 750 } 751 } 752 sendCancelUserConfirmationIntent(BluetoothDevice device)753 private void sendCancelUserConfirmationIntent(BluetoothDevice device) { 754 Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL); 755 intent.setPackage(getString(R.string.pairing_ui_package)); 756 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 757 intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 758 BluetoothDevice.REQUEST_TYPE_SIM_ACCESS); 759 sendBroadcast(intent, BLUETOOTH_PERM); 760 } 761 sendShutdownMessage()762 private void sendShutdownMessage() { 763 /* Any pending messages are no longer valid. 764 To speed up things, simply delete them. */ 765 if (mRemoveTimeoutMsg) { 766 Intent timeoutIntent = new Intent(USER_CONFIRM_TIMEOUT_ACTION); 767 sendBroadcast(timeoutIntent, BLUETOOTH_PERM); 768 mIsWaitingAuthorization = false; 769 cancelUserTimeoutAlarm(); 770 } 771 removeSdpRecord(); 772 mSessionStatusHandler.removeCallbacksAndMessages(null); 773 // Request release of all resources 774 mSessionStatusHandler.obtainMessage(SHUTDOWN).sendToTarget(); 775 } 776 sendConnectTimeoutMessage()777 private void sendConnectTimeoutMessage() { 778 if (DEBUG) { 779 Log.d(TAG, "sendConnectTimeoutMessage()"); 780 } 781 if (mSessionStatusHandler != null) { 782 Message msg = mSessionStatusHandler.obtainMessage(USER_TIMEOUT); 783 msg.sendToTarget(); 784 } // Can only be null during shutdown 785 } 786 787 private SapBroadcastReceiver mSapReceiver = new SapBroadcastReceiver(); 788 789 private class SapBroadcastReceiver extends BroadcastReceiver { 790 @Override onReceive(Context context, Intent intent)791 public void onReceive(Context context, Intent intent) { 792 793 if (VERBOSE) { 794 Log.v(TAG, "onReceive"); 795 } 796 String action = intent.getAction(); 797 if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { 798 int state = 799 intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 800 if (state == BluetoothAdapter.STATE_TURNING_OFF) { 801 if (DEBUG) { 802 Log.d(TAG, "STATE_TURNING_OFF"); 803 } 804 sendShutdownMessage(); 805 } else if (state == BluetoothAdapter.STATE_ON) { 806 if (DEBUG) { 807 Log.d(TAG, "STATE_ON"); 808 } 809 // start RFCOMM listener 810 mSessionStatusHandler.sendMessage( 811 mSessionStatusHandler.obtainMessage(START_LISTENER)); 812 } 813 return; 814 } 815 816 if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) { 817 Log.v(TAG, " - Received BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY"); 818 819 int requestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, -1); 820 if (requestType != BluetoothDevice.REQUEST_TYPE_SIM_ACCESS) { 821 return; 822 } 823 824 mIsWaitingAuthorization = false; 825 826 if (intent.getIntExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, 827 BluetoothDevice.CONNECTION_ACCESS_NO) 828 == BluetoothDevice.CONNECTION_ACCESS_YES) { 829 // bluetooth connection accepted by user 830 if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) { 831 boolean result = mRemoteDevice.setSimAccessPermission( 832 BluetoothDevice.ACCESS_ALLOWED); 833 if (VERBOSE) { 834 Log.v(TAG, "setSimAccessPermission(ACCESS_ALLOWED) result=" + result); 835 } 836 } 837 boolean result = setConnectionPolicy(mRemoteDevice, 838 BluetoothProfile.CONNECTION_POLICY_ALLOWED); 839 Log.d(TAG, "setConnectionPolicy ALLOWED, result = " + result); 840 841 try { 842 if (mConnSocket != null) { 843 // start obex server and rfcomm connection 844 startSapServerSession(); 845 } else { 846 stopSapServerSession(); 847 } 848 } catch (IOException ex) { 849 Log.e(TAG, "Caught the error: ", ex); 850 } 851 } else { 852 if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) { 853 boolean result = mRemoteDevice.setSimAccessPermission( 854 BluetoothDevice.ACCESS_REJECTED); 855 if (VERBOSE) { 856 Log.v(TAG, "setSimAccessPermission(ACCESS_REJECTED) result=" + result); 857 } 858 } 859 boolean result = setConnectionPolicy(mRemoteDevice, 860 BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 861 Log.d(TAG, "setConnectionPolicy FORBIDDEN, result = " + result); 862 // Ensure proper cleanup, and prepare for new connect. 863 mSessionStatusHandler.sendEmptyMessage(MSG_SERVERSESSION_CLOSE); 864 } 865 return; 866 } 867 868 if (action.equals(USER_CONFIRM_TIMEOUT_ACTION)) { 869 if (DEBUG) { 870 Log.d(TAG, "USER_CONFIRM_TIMEOUT_ACTION Received."); 871 } 872 // send us self a message about the timeout. 873 sendConnectTimeoutMessage(); 874 return; 875 } 876 877 if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED) && mIsWaitingAuthorization) { 878 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 879 880 if (mRemoteDevice == null || device == null) { 881 Log.i(TAG, "Unexpected error!"); 882 return; 883 } 884 885 if (DEBUG) { 886 Log.d(TAG, "ACL disconnected for " + device); 887 } 888 889 if (mRemoteDevice.equals(device)) { 890 if (mRemoveTimeoutMsg) { 891 // Send any pending timeout now, as ACL got disconnected. 892 mSessionStatusHandler.removeMessages(USER_TIMEOUT); 893 mSessionStatusHandler.obtainMessage(USER_TIMEOUT).sendToTarget(); 894 } 895 setState(BluetoothSap.STATE_DISCONNECTED); 896 // Ensure proper cleanup, and prepare for new connect. 897 mSessionStatusHandler.sendEmptyMessage(MSG_SERVERSESSION_CLOSE); 898 } 899 } 900 } 901 } 902 903 ; 904 905 //Binder object: Must be static class or memory leak may occur 906 907 /** 908 * This class implements the IBluetoothSap interface - or actually it validates the 909 * preconditions for calling the actual functionality in the SapService, and calls it. 910 */ 911 private static class SapBinder extends IBluetoothSap.Stub implements IProfileServiceBinder { 912 private SapService mService; 913 getService()914 private SapService getService() { 915 if (!Utils.checkCaller()) { 916 Log.w(TAG, "call not allowed for non-active user"); 917 return null; 918 } 919 920 if (mService != null && mService.isAvailable()) { 921 mService.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 922 "Need BLUETOOTH permission"); 923 return mService; 924 } 925 return null; 926 } 927 SapBinder(SapService service)928 SapBinder(SapService service) { 929 Log.v(TAG, "SapBinder()"); 930 mService = service; 931 } 932 933 @Override cleanup()934 public void cleanup() { 935 mService = null; 936 } 937 938 @Override getState()939 public int getState() { 940 Log.v(TAG, "getState()"); 941 SapService service = getService(); 942 if (service == null) { 943 return BluetoothSap.STATE_DISCONNECTED; 944 } 945 return getService().getState(); 946 } 947 948 @Override getClient()949 public BluetoothDevice getClient() { 950 Log.v(TAG, "getClient()"); 951 SapService service = getService(); 952 if (service == null) { 953 return null; 954 } 955 Log.v(TAG, "getClient() - returning " + service.getRemoteDevice()); 956 return service.getRemoteDevice(); 957 } 958 959 @Override isConnected(BluetoothDevice device)960 public boolean isConnected(BluetoothDevice device) { 961 Log.v(TAG, "isConnected()"); 962 SapService service = getService(); 963 if (service == null) { 964 return false; 965 } 966 return (service.getState() == BluetoothSap.STATE_CONNECTED && service.getRemoteDevice() 967 .equals(device)); 968 } 969 970 @Override connect(BluetoothDevice device)971 public boolean connect(BluetoothDevice device) { 972 Log.v(TAG, "connect()"); 973 SapService service = getService(); 974 if (service == null) { 975 return false; 976 } 977 return false; 978 } 979 980 @Override disconnect(BluetoothDevice device)981 public boolean disconnect(BluetoothDevice device) { 982 Log.v(TAG, "disconnect()"); 983 SapService service = getService(); 984 if (service == null) { 985 return false; 986 } 987 return service.disconnect(device); 988 } 989 990 @Override getConnectedDevices()991 public List<BluetoothDevice> getConnectedDevices() { 992 Log.v(TAG, "getConnectedDevices()"); 993 SapService service = getService(); 994 if (service == null) { 995 return new ArrayList<BluetoothDevice>(0); 996 } 997 return service.getConnectedDevices(); 998 } 999 1000 @Override getDevicesMatchingConnectionStates(int[] states)1001 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 1002 Log.v(TAG, "getDevicesMatchingConnectionStates()"); 1003 SapService service = getService(); 1004 if (service == null) { 1005 return new ArrayList<BluetoothDevice>(0); 1006 } 1007 return service.getDevicesMatchingConnectionStates(states); 1008 } 1009 1010 @Override getConnectionState(BluetoothDevice device)1011 public int getConnectionState(BluetoothDevice device) { 1012 Log.v(TAG, "getConnectionState()"); 1013 SapService service = getService(); 1014 if (service == null) { 1015 return BluetoothProfile.STATE_DISCONNECTED; 1016 } 1017 return service.getConnectionState(device); 1018 } 1019 1020 @Override setConnectionPolicy(BluetoothDevice device, int connectionPolicy)1021 public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { 1022 SapService service = getService(); 1023 if (service == null) { 1024 return false; 1025 } 1026 return service.setConnectionPolicy(device, connectionPolicy); 1027 } 1028 1029 @Override getConnectionPolicy(BluetoothDevice device)1030 public int getConnectionPolicy(BluetoothDevice device) { 1031 SapService service = getService(); 1032 if (service == null) { 1033 return BluetoothProfile.CONNECTION_POLICY_UNKNOWN; 1034 } 1035 return service.getConnectionPolicy(device); 1036 } 1037 } 1038 } 1039