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