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