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